Encryption + Undelete code base
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,116 @@
|
||||
package ru.vtosters.lite.encryption;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
import ru.vtosters.lite.encryption.processors.BeeCryptProcessor;
|
||||
import ru.vtosters.lite.encryption.processors.DefaultCoffeeProcessor;
|
||||
import ru.vtosters.lite.encryption.processors.DonateCoffeeProcessor;
|
||||
import ru.vtosters.lite.encryption.processors.MP3InvisibleProcessor;
|
||||
import ru.vtosters.lite.encryption.processors.VTostersAESProcessor;
|
||||
import ru.vtosters.lite.encryption.processors.VTostersProcessor;
|
||||
|
||||
public class EncryptProvider {
|
||||
public static List<IMProcessor> processors = new ArrayList<>();
|
||||
|
||||
public static IMProcessor getProcessorFor(int peerId) {
|
||||
IMProcessor enabled = null;
|
||||
for (IMProcessor processor: EncryptProvider.processors) {
|
||||
if (processor.isUsedToEncrypt(peerId)) {
|
||||
enabled = processor;
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public static String getBody(MsgFromUser msg) {
|
||||
return msg.E();
|
||||
}
|
||||
|
||||
public static int getPeerId(Msg msg) {
|
||||
return msg.b();
|
||||
}
|
||||
|
||||
// This will run through EVERY single processor available.
|
||||
public static String decryptMessage(MsgFromUser msg) {
|
||||
return decryptMessage(getBody(msg), getPeerId(msg));
|
||||
}
|
||||
|
||||
public static String decryptMessage(String msgBody, int peer) {
|
||||
try {
|
||||
for (IMProcessor processor : processors) {
|
||||
if ((processor.isUsed() || !processor.isPublic()) && processor.isEncrypted(msgBody) && (processor.isPublic() || getKeyForProcessor(processor, peer) != null))
|
||||
return "\uD83D\uDD12 " + processor.decode(msgBody, getKeyForProcessor(processor, peer));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return msgBody;
|
||||
}
|
||||
|
||||
private static byte[] getKeyForProcessor(IMProcessor processor, int peer) {
|
||||
if (processor.isPublic()) return null;
|
||||
String keyString = processor.getEncryptionKeyFor(peer);
|
||||
if (keyString == null) return null;
|
||||
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(keyString.getBytes());
|
||||
byte[] key = new byte[16];
|
||||
System.arraycopy(hash, 0, key, 0, key.length);
|
||||
return key;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return keyString.getBytes();
|
||||
}
|
||||
|
||||
// This will use only the processor which was chosen in chat menu [that's why ID is needed, bruh]
|
||||
public static String encryptMessage(MsgFromUser msg) {
|
||||
|
||||
String msgBody = getBody(msg);
|
||||
|
||||
Log.d("EncryptProvider", "encryptMessage: msg = " + msg.toString());
|
||||
Log.d("EncryptProvider", "encryptMessage: body = " + msgBody);
|
||||
Log.d("EncryptProvider", "encryptMessage: peerId = " + getPeerId(msg));
|
||||
|
||||
for (IMProcessor processor: processors) {
|
||||
int peer = getPeerId(msg);
|
||||
if (processor.isUsedToEncrypt(peer)) {
|
||||
return processor.encode(msgBody, getKeyForProcessor(processor, peer));
|
||||
}
|
||||
}
|
||||
|
||||
return msgBody;
|
||||
}
|
||||
|
||||
// For rendering UI
|
||||
public static List<Pair<String, String>> getUserVisibleEncoders() {
|
||||
List<Pair<String, String>> theList = new ArrayList<>();
|
||||
|
||||
for (IMProcessor processor: processors) {
|
||||
if (processor.isPublic()) theList.add(new Pair<>("VT_IMDecode_"+processor.getPrefKey(), processor.getUIName()));
|
||||
}
|
||||
|
||||
return theList;
|
||||
}
|
||||
|
||||
static {
|
||||
processors.add(new VTostersProcessor());
|
||||
processors.add(new VTostersAESProcessor());
|
||||
processors.add(new DefaultCoffeeProcessor());
|
||||
processors.add(new DonateCoffeeProcessor());
|
||||
processors.add(new BeeCryptProcessor());
|
||||
processors.add(new MP3InvisibleProcessor());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package ru.vtosters.lite.encryption.base;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.BooleanFalse;
|
||||
import static ru.vtosters.lite.utils.Preferences.BooleanTrue;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import ru.vtosters.lite.utils.Globals;
|
||||
|
||||
public abstract class IMProcessor {
|
||||
// By default it checks start and end tag.
|
||||
public boolean isEncrypted(String source) {
|
||||
//Log.d("IMProcessor", "Checking if encrypted: "+source+" / "+getUIName());
|
||||
return source.startsWith(startTag()) && source.endsWith(endTag());
|
||||
}
|
||||
|
||||
// Key can be null - if it's a public processor
|
||||
@NonNull protected abstract String encodeInternal(@NonNull String source, @Nullable byte[] key);
|
||||
@NonNull protected abstract String decodeInternal(@NonNull String source, @Nullable byte[] key);
|
||||
|
||||
// Automatically removes tags. Magic!
|
||||
@NonNull
|
||||
public String encode(@NonNull String source, @Nullable byte[] key) {
|
||||
//Log.d("IMProcessor", "Encoding "+source);
|
||||
return startTag() + encodeInternal(source, key) + endTag();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String decode(@NonNull String source, @Nullable byte[] key) {
|
||||
//Log.d("IMProcessor", "Decoding");
|
||||
return decodeInternal(source.substring(startTag().length(), source.length() - endTag().length()), key);
|
||||
}
|
||||
|
||||
// Public - no key required.
|
||||
public boolean isPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// UI thing
|
||||
@NonNull abstract public String getUIName();
|
||||
@NonNull abstract public String getPrefKey();
|
||||
|
||||
@NonNull public String startTag() {
|
||||
return "";
|
||||
}
|
||||
@NonNull public String endTag() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isUsed() {
|
||||
//Log.d("IMProcessor", "Checking if decoded with "+getUIName());
|
||||
return BooleanTrue("VT_IMDecode_"+getPrefKey());
|
||||
}
|
||||
|
||||
public boolean isUsedToEncrypt(int id) {
|
||||
//Log.d("IMProcessor", "Checking if "+id+" is ready to be encrypted with "+getUIName());
|
||||
return BooleanFalse("VT_IMEncode_"+getPrefKey()+"_"+id);
|
||||
}
|
||||
|
||||
public void enableEncryptFor(int id) {
|
||||
Globals.getPrefs().edit().putBoolean("VT_IMEncode_"+getPrefKey()+"_"+id, true).apply();
|
||||
}
|
||||
|
||||
public void disableEncryptFor(int id) {
|
||||
Globals.getPrefs().edit().putBoolean("VT_IMEncode_"+getPrefKey()+"_"+id, false).apply();
|
||||
}
|
||||
|
||||
public void setEncryptionKeyFor(int id, @Nullable String key) {
|
||||
if (key == null || key.isEmpty()) key = "VTAesDefault";
|
||||
Globals.getPrefs().edit().putString("VT_IMEncodeKey_"+getPrefKey()+"_"+id, key).apply();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getEncryptionKeyFor(int id) {
|
||||
return Globals.getPrefs().getString("VT_IMEncodeKey_"+getPrefKey()+"_"+id, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package ru.vtosters.lite.encryption.processors;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
|
||||
public class BeeCryptProcessor extends IMProcessor {
|
||||
private static final String BC_CHARSET = "жъЖЪ";
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String encodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
String a = Base64.encodeToString(source.getBytes(StandardCharsets.UTF_8), 2);
|
||||
StringBuilder res = new StringBuilder();
|
||||
for (int i = 0; i < a.length(); i++) {
|
||||
StringBuilder bintxt = new StringBuilder();
|
||||
int c = a.charAt(i);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
bintxt.insert(0, BC_CHARSET.charAt(c % 4));
|
||||
c /= 4;
|
||||
}
|
||||
res.append(bintxt);
|
||||
}
|
||||
return res.toString();
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted(String source) {
|
||||
return source.matches("[жъЖЪ]{16,}");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String decodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
StringBuilder b64 = new StringBuilder();
|
||||
int i = 0;
|
||||
while (i < source.length() - 3) {
|
||||
try {
|
||||
String bintxt = source.substring(i, i + 4);
|
||||
int c = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
c = (c * 4) + Math.max(0, BC_CHARSET.indexOf(bintxt.charAt(j)));
|
||||
}
|
||||
b64.append((char) c);
|
||||
i += 4;
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
return source;
|
||||
}
|
||||
}
|
||||
return new String(Base64.decode(b64.toString(), 2), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUIName() {
|
||||
return "MP3 [beecrypt]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "mp3_bc";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package ru.vtosters.lite.encryption.processors;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
|
||||
public class DefaultCoffeeProcessor extends IMProcessor {
|
||||
private final static String KEY = "stupidUsersMustD";
|
||||
private static Cipher dCipher, eCipher;
|
||||
|
||||
static {
|
||||
try {
|
||||
SecretKeySpec key = new SecretKeySpec(KEY.getBytes(), "AES");
|
||||
|
||||
dCipher = Cipher.getInstance("AES");
|
||||
dCipher.init(Cipher.DECRYPT_MODE, key);
|
||||
|
||||
eCipher = Cipher.getInstance("AES");
|
||||
eCipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String toHex(String text) {
|
||||
char[] chars = text.toCharArray();
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (char aChar : chars) {
|
||||
String s = Integer.toHexString(aChar);
|
||||
if (s.length() < 2) s = "0" + s;
|
||||
str.append(s.toUpperCase()).append(" ");
|
||||
}
|
||||
|
||||
String string = str.toString();
|
||||
return string.substring(0, string.length()-1);
|
||||
}
|
||||
|
||||
private String fromHex(String text) {
|
||||
text = text.replace(" ", "");
|
||||
char[] chars = text.toCharArray();
|
||||
char[] chars2 = new char[chars.length/2];
|
||||
for (int i = 0; i < chars.length; i+=2) {
|
||||
String c = String.valueOf(chars[i]) + chars[i + 1];
|
||||
chars2[i/2] = (char) Integer.parseInt(c, 16);
|
||||
}
|
||||
|
||||
return new String(chars2);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String encodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
return toHex(Base64.encodeToString(eCipher.doFinal(source.getBytes()), 0));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String decodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
return new String(dCipher.doFinal(Base64.decode(fromHex(source), 0)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String startTag() {
|
||||
return "VK CO FF EE ";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String endTag() {
|
||||
return " VK CO FF EE";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUIName() {
|
||||
return "VK Coffee [default]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "coffee_default";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package ru.vtosters.lite.encryption.processors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class DonateCoffeeProcessor extends DefaultCoffeeProcessor {
|
||||
@Override
|
||||
@NonNull
|
||||
public String startTag() {
|
||||
return "II ";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String endTag() {
|
||||
return " II";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUIName() {
|
||||
return "VK Coffee [hidden]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "coffee_donate";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ru.vtosters.lite.encryption.processors;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
|
||||
public class MP3InvisibleProcessor extends IMProcessor {
|
||||
@NonNull
|
||||
@Override
|
||||
protected String encodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
byte[] bytes = source.getBytes(StandardCharsets.UTF_8);
|
||||
java.lang.String[] plainText = new String[bytes.length];
|
||||
for (int i = 0; i < plainText.length; i++) {
|
||||
plainText[i] = toStr(bytes[i] & 255, " ");
|
||||
}
|
||||
return " " + TextUtils.join(" ", plainText);
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String decodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
java.lang.String[] t = source.replaceAll("^" + " ", "").split(" ");
|
||||
byte[] plainText = new byte[t.length];
|
||||
for (int i = 0; i < plainText.length; i++) {
|
||||
plainText[i] = (byte) toNum(t[i], " ");
|
||||
}
|
||||
return new String(plainText, StandardCharsets.UTF_8);
|
||||
} catch (java.lang.Exception e) {
|
||||
e.printStackTrace();
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
private static String toStr(int a, String cc) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
while (a > 0) {
|
||||
s.insert(0, cc.charAt(a % cc.length()));
|
||||
a /= cc.length();
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
private static int toNum(String a, String cc) {
|
||||
int n = 0;
|
||||
for (int i = 0; i < a.length(); i++) {
|
||||
int start = (a.length() - i) - 1;
|
||||
n = (int) (((double) n) + (((double) cc.indexOf(a.substring(start, start + 1))) * Math.pow(cc.length(), i)));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted(String source) {
|
||||
return source.matches("^" + " " + "([" + " " + "\\s]*)");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUIName() {
|
||||
return "MP3 [invisible]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "mp3";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package ru.vtosters.lite.encryption.processors;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
import ru.vtosters.lite.utils.Globals;
|
||||
|
||||
public class VTostersAESProcessor extends IMProcessor {
|
||||
private final static String CIPHER_INSTANCE = "AES/CBC/PKCS7Padding";
|
||||
private final static String KEY_METHOD = "AES";
|
||||
|
||||
private HashMap<byte[], Cipher> decodeMap = new HashMap<>(), encodeMap = new HashMap<>();
|
||||
|
||||
public void free(byte[] key) {
|
||||
decodeMap.remove(key);
|
||||
encodeMap.remove(key);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Cipher wrapEncoder(byte[] key) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
if (encodeMap.containsKey(key)) return encodeMap.get(key);
|
||||
|
||||
Triple<Cipher, SecretKeySpec, IvParameterSpec> encodeCipher = getBaseCipher(key);
|
||||
encodeCipher.first.init(Cipher.ENCRYPT_MODE, encodeCipher.second, encodeCipher.third);
|
||||
encodeMap.put(key, encodeCipher.first);
|
||||
|
||||
return encodeCipher.first;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Cipher wrapDecoder(byte[] key) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
if (decodeMap.containsKey(key)) return decodeMap.get(key);
|
||||
|
||||
Triple<Cipher, SecretKeySpec, IvParameterSpec> decodeCipher = getBaseCipher(key);
|
||||
decodeCipher.first.init(Cipher.DECRYPT_MODE, decodeCipher.second, decodeCipher.third);
|
||||
decodeMap.put(key, decodeCipher.first);
|
||||
|
||||
return decodeCipher.first;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Triple<Cipher, SecretKeySpec, IvParameterSpec> getBaseCipher(byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException {
|
||||
byte[] off = new byte[16];
|
||||
System.arraycopy(key, 0, off, 0, off.length);
|
||||
return new Triple<>(Cipher.getInstance(CIPHER_INSTANCE), new SecretKeySpec(key, KEY_METHOD), new IvParameterSpec(off));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String encodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
return Base64.encodeToString(wrapEncoder(key).doFinal(source.getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String decodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
try {
|
||||
return new String(wrapDecoder(key).doFinal(Base64.decode(source, Base64.DEFAULT)), StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String startTag() {
|
||||
return "VT0ST3RS [AES] ";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String endTag() {
|
||||
return " VT0ST3RS [AES]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUIName() {
|
||||
return "VTosters [AES]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "vtaes";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getEncryptionKeyFor(int id) {
|
||||
return Globals.getPrefs().getString("VT_IMEncodeKey_"+getPrefKey()+"_"+id, "VTAesDefault");
|
||||
}
|
||||
|
||||
public static class Triple<F, S, T> {
|
||||
public final F first;
|
||||
public final S second;
|
||||
public final T third;
|
||||
|
||||
public Triple(F first, S second, T third) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.third = third;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ru.vtosters.lite.encryption.processors;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
|
||||
public class VTostersProcessor extends IMProcessor {
|
||||
@NonNull
|
||||
@Override
|
||||
protected String encodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
return Base64.encodeToString(source.getBytes(), Base64.DEFAULT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String decodeInternal(@NonNull String source, @Nullable byte[] key) {
|
||||
return new String(Base64.decode(source, Base64.DEFAULT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String startTag() {
|
||||
return "VT0ST3RS ";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String endTag() {
|
||||
return " VT0ST3RS";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUIName() {
|
||||
return "VTosters Classique [Base64]";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPrefKey() {
|
||||
return "vt64";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.utils.Globals.*;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.Globals.getApplicationName;
|
||||
import static ru.vtosters.lite.utils.Globals.getContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.VERSIONNAME;
|
||||
import static ru.vtosters.lite.utils.Preferences.oldabout;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.utils.Globals.getContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.BooleanFalse;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.vk.im.engine.events.OnMsgUpdateEvent;
|
||||
import com.vk.im.engine.internal.longpoll.a.MsgDeleteLpTask;
|
||||
import com.vk.im.engine.internal.storage.CacheEnvironment;
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.engine.models.messages.NestedMsg;
|
||||
import com.vk.libsqliteext.CustomSqliteExtensions;
|
||||
|
||||
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
|
||||
public class DeletedMessagesHandler {
|
||||
|
||||
private static List<Integer> sDeletedMessagesList = new ArrayList<>();
|
||||
|
||||
private static final String DELETED_PREFIX = "\uD83D\uDDD1 ";
|
||||
|
||||
private static SQLiteDatabase sVKSQLiteDatabase;
|
||||
private static int sBodyIndex = -1;
|
||||
private static DeletedMessagesDBHelper sToasterDatabase;
|
||||
|
||||
public static void reloadMessagesList() {
|
||||
if (sToasterDatabase == null) {
|
||||
sToasterDatabase = new DeletedMessagesDBHelper();
|
||||
}
|
||||
sDeletedMessagesList = new ArrayList<>(sToasterDatabase.loadAllMessages());
|
||||
}
|
||||
|
||||
public static void grabVKDatabase(CacheEnvironment storageEnvironment) {
|
||||
sVKSQLiteDatabase = storageEnvironment.b();
|
||||
}
|
||||
|
||||
public static boolean hook() {
|
||||
return BooleanFalse("hook_deleted_messages");
|
||||
}
|
||||
|
||||
public static void setBodyDBParser(Msg msg) {
|
||||
if (!(msg instanceof MsgFromUser)) return;
|
||||
|
||||
for (Integer integer : sDeletedMessagesList) {
|
||||
MsgFromUser msgFromUser = (MsgFromUser) msg;
|
||||
checkForNestedMsg(msgFromUser.g);
|
||||
if (integer == msg.d) {
|
||||
editTextOfMsg((MsgFromUser) msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkForNestedMsg(List<NestedMsg> nestedMsgs) {
|
||||
for (NestedMsg nestedMsg : nestedMsgs) {
|
||||
if (!nestedMsg.i.isEmpty()) checkForNestedMsg(nestedMsg.i);
|
||||
|
||||
nestedMsg.b(EncryptProvider.decryptMessage(nestedMsg.E(), nestedMsg.h().c));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void editTextOfMsg(MsgFromUser msgFromUser) {
|
||||
if (!msgFromUser.e.startsWith(DELETED_PREFIX)) {
|
||||
msgFromUser.e = DELETED_PREFIX + EncryptProvider.decryptMessage(msgFromUser);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateDialog(MsgDeleteLpTask msgDeleteLpTask) {
|
||||
Cursor c = getMessageFromDatabaseById(msgDeleteLpTask.c);
|
||||
if (c == null) return;
|
||||
|
||||
int localId = c.getInt(c.getColumnIndex("local_id"));
|
||||
|
||||
String str = DeletedMessagesHandler.class.getSimpleName();
|
||||
msgDeleteLpTask.a.a(str, new OnMsgUpdateEvent(str, msgDeleteLpTask.b, localId));
|
||||
}
|
||||
|
||||
public static void hookDeletedMessageId(MsgDeleteLpTask msgDeleteLpTask) {
|
||||
if (!hook()) return;
|
||||
|
||||
int messageId = msgDeleteLpTask.c;
|
||||
|
||||
Cursor c = getMessageFromDatabaseById(messageId);
|
||||
if (c == null) return;
|
||||
if (sBodyIndex == -1) sBodyIndex = c.getColumnIndex("body");
|
||||
if (TextUtils.isEmpty(c.getString(sBodyIndex))) {
|
||||
deleteMessageFromDB(messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
sDeletedMessagesList.add(messageId);
|
||||
sToasterDatabase.saveDeletedMessage(messageId);
|
||||
}
|
||||
|
||||
public static Cursor getMessageFromDatabaseById(int messageId) {
|
||||
String query = "SELECT * FROM messages WHERE vk_id = " + messageId;
|
||||
Cursor c = CustomSqliteExtensions.a(sVKSQLiteDatabase, query);
|
||||
if (!c.moveToFirst()) return null;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static void deleteMessageFromDB(int messageId) {
|
||||
sVKSQLiteDatabase.execSQL("DELETE FROM messages WHERE vk_id = " + messageId);
|
||||
}
|
||||
|
||||
public static class DeletedMessagesDBHelper extends SQLiteOpenHelper {
|
||||
|
||||
public DeletedMessagesDBHelper() {
|
||||
super(getContext(), "deleted_msgs", null, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(android.database.sqlite.SQLiteDatabase db) {
|
||||
db.execSQL("create table deleted_msgs (id integer primary key, msgId integer)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(android.database.sqlite.SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
|
||||
}
|
||||
|
||||
public void saveDeletedMessage(int msgId) {
|
||||
android.database.sqlite.SQLiteDatabase sqLiteDatabase = getWritableDatabase();
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put("msgId", msgId);
|
||||
|
||||
sqLiteDatabase.insert("deleted_msgs", null, contentValues);
|
||||
sqLiteDatabase.close();
|
||||
}
|
||||
|
||||
public List<Integer> loadAllMessages() {
|
||||
List<Integer> msgIdsList = new ArrayList<>();
|
||||
|
||||
Cursor cursor = getReadableDatabase().query("deleted_msgs", null, null, null, null, null, null);
|
||||
if (cursor.moveToFirst()) {
|
||||
int msgIdIndex = cursor.getColumnIndex("msgId");
|
||||
|
||||
do {
|
||||
msgIdsList.add(cursor.getInt(msgIdIndex));
|
||||
} while (cursor.moveToNext());
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return msgIdsList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.utils.Globals.getContext;
|
||||
import static ru.vtosters.lite.utils.Globals.isEmpty;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.Preferences.isEnableExternalOpening;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
|
||||
@@ -34,6 +34,13 @@ import java.util.Locale;
|
||||
public class Globals {
|
||||
private static final List<Activity> activities = new ArrayList<>();
|
||||
|
||||
static SharedPreferences prefs = getContext().getSharedPreferences("com.vtosters.lite_preferences", Context.MODE_PRIVATE);
|
||||
|
||||
public static SharedPreferences getPrefs() {
|
||||
if (prefs == null) prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
return prefs;
|
||||
}
|
||||
|
||||
// Current UserId
|
||||
public static int getUserId() {
|
||||
return VKAccountManager.b().a();
|
||||
@@ -207,6 +214,11 @@ public class Globals {
|
||||
});
|
||||
}
|
||||
|
||||
public static Activity getCurrentActivity() {
|
||||
if (activities.size() == 0) return null;
|
||||
else return activities.get(0);
|
||||
}
|
||||
|
||||
public static String getApplicationName() {
|
||||
return getContext().getApplicationInfo().loadLabel(getContext().getPackageManager()).toString();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.ui.fragments.multiaccount.MultiAccountManager.migrate;
|
||||
import static ru.vtosters.lite.utils.Globals.*;
|
||||
import static ru.vtosters.lite.utils.Newsfeed.*;
|
||||
import static ru.vtosters.lite.utils.Proxy.*;
|
||||
import static ru.vtosters.lite.utils.Globals.fixGapps;
|
||||
import static ru.vtosters.lite.utils.Globals.getContext;
|
||||
import static ru.vtosters.lite.utils.Globals.getPreferences;
|
||||
import static ru.vtosters.lite.utils.Globals.registerActivities;
|
||||
import static ru.vtosters.lite.utils.Newsfeed.setupFilters;
|
||||
import static ru.vtosters.lite.utils.Proxy.setProxy;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.utils.Globals.*;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.Globals.getPreferences;
|
||||
import static ru.vtosters.lite.utils.Preferences.BooleanFalse;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.utils.About.*;
|
||||
import static ru.vtosters.lite.utils.Globals.*;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.Proxy.*;
|
||||
import static ru.vtosters.lite.utils.About.getBuildNumber;
|
||||
import static ru.vtosters.lite.utils.Globals.getPreferences;
|
||||
import static ru.vtosters.lite.utils.Globals.getUserSecret;
|
||||
import static ru.vtosters.lite.utils.Globals.getUserToken;
|
||||
import static ru.vtosters.lite.utils.Preferences.dev;
|
||||
import static ru.vtosters.lite.utils.Preferences.getLocale;
|
||||
import static ru.vtosters.lite.utils.Preferences.vksans;
|
||||
import static ru.vtosters.lite.utils.Proxy.proxy;
|
||||
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.utils.Globals.*;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.Globals.getContext;
|
||||
import static ru.vtosters.lite.utils.Globals.getPreferences;
|
||||
import static ru.vtosters.lite.utils.Preferences.color_grishka;
|
||||
import static ru.vtosters.lite.utils.Preferences.isBGStickersEnabled;
|
||||
import static ru.vtosters.lite.utils.Preferences.navbar;
|
||||
import static ru.vtosters.lite.utils.Preferences.vksans;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
|
||||
move-result-object v6
|
||||
|
||||
invoke-static {p0}, Lru/vtosters/lite/encryption/EncryptProvider;->encryptMessage(Lcom/vk/im/engine/models/messages/MsgFromUser;)Ljava/lang/String;
|
||||
|
||||
move-result-object v6
|
||||
|
||||
invoke-interface {v2, v5, v6}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
|
||||
.line 108
|
||||
|
||||
@@ -36,37 +36,37 @@
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private c:I
|
||||
.field public c:I
|
||||
|
||||
.field private d:I
|
||||
.field public d:I
|
||||
|
||||
.field private e:I
|
||||
.field public e:I
|
||||
|
||||
.field private f:I
|
||||
.field public f:I
|
||||
|
||||
.field private g:I
|
||||
.field public g:I
|
||||
|
||||
.field private h:J
|
||||
.field public h:J
|
||||
|
||||
.field private i:Lcom/vk/im/engine/models/Member;
|
||||
.field public i:Lcom/vk/im/engine/models/Member;
|
||||
|
||||
.field private j:Z
|
||||
.field public j:Z
|
||||
|
||||
.field private k:Z
|
||||
.field public k:Z
|
||||
|
||||
.field private l:Z
|
||||
.field public l:Z
|
||||
|
||||
.field private m:Z
|
||||
.field public m:Z
|
||||
|
||||
.field private n:Lcom/vk/im/engine/models/messages/MsgSyncState;
|
||||
.field public n:Lcom/vk/im/engine/models/messages/MsgSyncState;
|
||||
|
||||
.field private o:Lcom/vk/im/engine/models/Weight;
|
||||
.field public o:Lcom/vk/im/engine/models/Weight;
|
||||
|
||||
.field private p:Z
|
||||
.field public p:Z
|
||||
|
||||
.field private q:Z
|
||||
.field public q:Z
|
||||
|
||||
.field private r:I
|
||||
.field public r:I
|
||||
|
||||
|
||||
# direct methods
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private d:Ljava/lang/String;
|
||||
.field public d:Ljava/lang/String;
|
||||
|
||||
.field private e:Ljava/lang/String;
|
||||
.field public e:Ljava/lang/String;
|
||||
|
||||
.field private f:Ljava/util/List;
|
||||
.field public f:Ljava/util/List;
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/util/List<",
|
||||
@@ -43,7 +43,7 @@
|
||||
.end annotation
|
||||
.end field
|
||||
|
||||
.field private g:Ljava/util/List;
|
||||
.field public g:Ljava/util/List;
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/util/List<",
|
||||
@@ -53,11 +53,11 @@
|
||||
.end annotation
|
||||
.end field
|
||||
|
||||
.field private h:Ljava/lang/String;
|
||||
.field public h:Ljava/lang/String;
|
||||
|
||||
.field private i:Ljava/lang/String;
|
||||
.field public i:Ljava/lang/String;
|
||||
|
||||
.field private j:Ljava/lang/String;
|
||||
.field public j:Ljava/lang/String;
|
||||
|
||||
|
||||
# direct methods
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private final a:Lcom/vk/im/engine/ImEnvironment;
|
||||
.field public final a:Lcom/vk/im/engine/ImEnvironment;
|
||||
|
||||
.field private final b:I
|
||||
.field public final b:I
|
||||
|
||||
.field private final c:I
|
||||
.field public final c:I
|
||||
|
||||
|
||||
# direct methods
|
||||
|
||||
+2
@@ -21,6 +21,8 @@
|
||||
.method public constructor <init>(Lcom/vk/im/engine/internal/storage/CacheEnvironment;)V
|
||||
.locals 7
|
||||
|
||||
invoke-static {p1}, Lru/vtosters/lite/utils/DeletedMessagesHandler;->grabVKDatabase(Lcom/vk/im/engine/internal/storage/CacheEnvironment;)V
|
||||
|
||||
const-string v0, "env"
|
||||
|
||||
invoke-static {p1, v0}, Lkotlin/jvm/internal/Intrinsics;->b(Ljava/lang/Object;Ljava/lang/String;)V
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private b:Lcom/vk/im/engine/models/MemberType;
|
||||
.field public b:Lcom/vk/im/engine/models/MemberType;
|
||||
|
||||
.field private c:I
|
||||
.field public c:I
|
||||
|
||||
|
||||
# direct methods
|
||||
|
||||
@@ -31,19 +31,19 @@
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private b:Lcom/vk/im/engine/models/messages/NestedMsg$Type;
|
||||
.field public b:Lcom/vk/im/engine/models/messages/NestedMsg$Type;
|
||||
|
||||
.field private c:I
|
||||
.field public c:I
|
||||
|
||||
.field private d:I
|
||||
.field public d:I
|
||||
|
||||
.field private e:Lcom/vk/im/engine/models/Member;
|
||||
.field public e:Lcom/vk/im/engine/models/Member;
|
||||
|
||||
.field private f:Ljava/lang/String;
|
||||
.field public f:Ljava/lang/String;
|
||||
|
||||
.field private g:Ljava/lang/String;
|
||||
.field public g:Ljava/lang/String;
|
||||
|
||||
.field private h:Ljava/util/List;
|
||||
.field public h:Ljava/util/List;
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/util/List<",
|
||||
@@ -53,7 +53,7 @@
|
||||
.end annotation
|
||||
.end field
|
||||
|
||||
.field private i:Ljava/util/List;
|
||||
.field public i:Ljava/util/List;
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/util/List<",
|
||||
@@ -63,7 +63,7 @@
|
||||
.end annotation
|
||||
.end field
|
||||
|
||||
.field private j:J
|
||||
.field public j:J
|
||||
|
||||
|
||||
# direct methods
|
||||
|
||||
Reference in New Issue
Block a user