mirror of https://github.com/NekoX-Dev/NekoX.git
This commit is contained in:
parent
7d39be9cc0
commit
c19a079ca7
|
@ -9,13 +9,13 @@ jobs:
|
|||
fossBuild:
|
||||
name: Foss Build
|
||||
runs-on: ubuntu-latest
|
||||
if: "contains(github.event.head_commit.message, '[RELEASE]') || contains(github.event.head_commit.message, '[N]')"
|
||||
if: "contains(github.event.head_commit.message, '[RELEASE]')"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle
|
||||
key: gradle-${{ hashFiles('**/*.gradle') }}
|
||||
key: native-${{ hashFiles('**/*.gradle') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- run: git submodule update --init --recursive
|
||||
|
@ -73,7 +73,7 @@ jobs:
|
|||
|
||||
./patch_boringssl.sh
|
||||
|
||||
[ -d "patch_boringssl/build" ] || ./build_boringssl.sh
|
||||
[ -d "boringssl/build" ] || ./build_boringssl.sh
|
||||
|
||||
- name: assemble
|
||||
run: |
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
name: Native Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
nativeBuild:
|
||||
name: Native Build
|
||||
runs-on: ubuntu-latest
|
||||
if: "contains(github.event.head_commit.message, '[N]')"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle
|
||||
key: native-${{ hashFiles('**/*.gradle') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- run: git submodule update --init --recursive
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: TMessagesProj/jni/boringssl/build
|
||||
key: boringssl-${{ hashFiles('TMessagesProj/jni/boringssl/.git') }}
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: TMessagesProj/jni/ffmpeg/build
|
||||
key: ffmpeg-${{ hashFiles('TMessagesProj/jni/ffmpeg/.git') }}
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Build native libraries
|
||||
run: |
|
||||
|
||||
cd TMessagesProj/jni
|
||||
|
||||
while :
|
||||
do
|
||||
sudo apt-get install -y ninja-build && break
|
||||
sleep 5
|
||||
done
|
||||
|
||||
export NDK=$ANDROID_HOME/ndk-bundle
|
||||
export NINJA_PATH=/usr/bin/ninja
|
||||
export PATH=`echo $ANDROID_HOME/cmake/*/bin`:$PATH
|
||||
|
||||
[ -d "ffmpeg/build" ] || ./build_ffmpeg_clang.sh
|
||||
|
||||
./patch_ffmpeg.sh
|
||||
|
||||
./patch_boringssl.sh
|
||||
|
||||
[ -d "boringssl/build" ] || ./build_boringssl.sh
|
||||
|
||||
- name: assemble
|
||||
run: |
|
||||
sudo bash <<EOF
|
||||
export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}" &&
|
||||
./gradlew assembleAfatFoss
|
||||
EOF
|
||||
ls TMessagesProj/build/outputs/apk
|
||||
echo ::set-env name=APK_FILE::$(find TMessagesProj/build/outputs/apk -name "*universal*")
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: NekoX-Foss
|
||||
path: ${{ env.APK_FILE }}
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: Boringssl Library
|
||||
path: "TMessagesProj/jni/boringssl/build"
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: Ffmpeg Library
|
||||
path: "TMessagesProj/jni/ffmpeg/build"
|
|
@ -111,6 +111,7 @@ void Handshake::cleanupHandshake() {
|
|||
void Handshake::clearServerPublicKey() {
|
||||
|
||||
serverPublicKeys.clear();
|
||||
clearServerPublicKey();
|
||||
|
||||
}
|
||||
|
||||
|
@ -480,6 +481,8 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (LOGS_ENABLED) DEBUG_D("publicKey: %s, fingerprint: %lld",key.c_str(),keyFingerprint);
|
||||
|
||||
authServerNonce = new ByteArray(result->server_nonce.get());
|
||||
|
||||
uint64_t pq = ((uint64_t) (result->pq->bytes[0] & 0xff) << 56) |
|
||||
|
|
|
@ -33,13 +33,17 @@ import org.telegram.tgnet.TLRPC;
|
|||
import org.telegram.ui.Components.ForegroundDetector;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import tw.nekomimi.nekogram.ExternalGcm;
|
||||
import tw.nekomimi.nekogram.NekoConfig;
|
||||
import tw.nekomimi.nekogram.utils.EnvUtil;
|
||||
import tw.nekomimi.nekogram.utils.FileUtil;
|
||||
import tw.nekomimi.nekogram.utils.ProxyUtil;
|
||||
import tw.nekomimi.nekogram.utils.UIUtil;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
public class ApplicationLoader extends Application {
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
|
@ -62,12 +66,103 @@ public class ApplicationLoader extends Application {
|
|||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
if (SDK_INT >= Build.VERSION_CODES.P) {
|
||||
Reflection.unseal(base);
|
||||
}
|
||||
super.attachBaseContext(base);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
MultiDex.install(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author weishu
|
||||
* @date 2018/6/7.
|
||||
*/
|
||||
public static class Reflection {
|
||||
private static final String TAG = "Reflection";
|
||||
|
||||
private static Object sVmRuntime;
|
||||
private static Method setHiddenApiExemptions;
|
||||
|
||||
static {
|
||||
if (SDK_INT >= Build.VERSION_CODES.P) {
|
||||
try {
|
||||
Method forName = Class.class.getDeclaredMethod("forName", String.class);
|
||||
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
|
||||
|
||||
Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
|
||||
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
|
||||
setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
|
||||
sVmRuntime = getRuntime.invoke(null);
|
||||
} catch (Throwable e) {
|
||||
FileLog.e("reflect bootstrap failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int UNKNOWN = -9999;
|
||||
|
||||
private static final int ERROR_SET_APPLICATION_FAILED = -20;
|
||||
|
||||
private static final int ERROR_EXEMPT_FAILED = -21;
|
||||
|
||||
private static int unsealed = UNKNOWN;
|
||||
|
||||
public static int unseal(Context context) {
|
||||
if (SDK_INT < 28) {
|
||||
// Below Android P, ignore
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try exempt API first.
|
||||
if (exemptAll()) {
|
||||
return 0;
|
||||
} else {
|
||||
return ERROR_EXEMPT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* make the method exempted from hidden API check.
|
||||
*
|
||||
* @param method the method signature prefix.
|
||||
* @return true if success.
|
||||
*/
|
||||
public static boolean exempt(String method) {
|
||||
return exempt(new String[]{method});
|
||||
}
|
||||
|
||||
/**
|
||||
* make specific methods exempted from hidden API check.
|
||||
*
|
||||
* @param methods the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L"
|
||||
* @return true if success
|
||||
*/
|
||||
public static boolean exempt(String... methods) {
|
||||
if (sVmRuntime == null || setHiddenApiExemptions == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all hidden API exempted.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
public static boolean exemptAll() {
|
||||
return exempt(new String[]{"L"});
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SdCardPath")
|
||||
public static File getDataDirFixed() {
|
||||
try {
|
||||
|
@ -220,11 +315,22 @@ public class ApplicationLoader extends Application {
|
|||
applicationHandler = new Handler(applicationContext.getMainLooper());
|
||||
|
||||
startPushService();
|
||||
|
||||
try {
|
||||
|
||||
EnvUtil.doTest();
|
||||
|
||||
}catch (Exception e) {
|
||||
|
||||
FileLog.e("EnvUtil test Failed",e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void startPushService() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return; // USE NOTIF LISTENER
|
||||
}
|
||||
SharedPreferences preferences = MessagesController.getGlobalNotificationsSettings();
|
||||
|
@ -236,7 +342,7 @@ public class ApplicationLoader extends Application {
|
|||
}
|
||||
if (enabled) {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && NekoConfig.residentNotification) {
|
||||
if (SDK_INT >= Build.VERSION_CODES.O && NekoConfig.residentNotification) {
|
||||
applicationContext.startForegroundService(new Intent(applicationContext, NotificationsService.class));
|
||||
} else {
|
||||
applicationContext.startService(new Intent(applicationContext, NotificationsService.class));
|
||||
|
|
|
@ -112,10 +112,8 @@ import org.telegram.ui.Components.SlideView;
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.KeyFactory;
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -134,6 +132,7 @@ import tw.nekomimi.nekogram.BottomBuilder;
|
|||
import tw.nekomimi.nekogram.DataCenter;
|
||||
import tw.nekomimi.nekogram.EditTextAutoFill;
|
||||
import tw.nekomimi.nekogram.NekoXConfig;
|
||||
import tw.nekomimi.nekogram.parts.PKCS1Pub;
|
||||
import tw.nekomimi.nekogram.utils.AlertUtil;
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
|
@ -410,7 +409,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
});
|
||||
|
||||
builder.addRadioItem(LocaleController.getString("CustomApiOffical", R.string.CustomApiOffical), NekoXConfig.customApi == 1, (cell) -> {
|
||||
builder.addRadioItem(LocaleController.getString("CustomApiOfficial", R.string.CustomApiOfficial), NekoXConfig.customApi == 1, (cell) -> {
|
||||
|
||||
targetApi.set(1);
|
||||
|
||||
|
@ -543,9 +542,9 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
EditText[] inputs = new EditText[6];
|
||||
|
||||
builder.addTitle("Custom Backend",
|
||||
builder.addTitle(LocaleController.getString("CustomBackend",R.string.CustomBackend),
|
||||
true,
|
||||
"~");
|
||||
LocaleController.getString("CustomBackendNotice",R.string.CustomBackendNotice));
|
||||
|
||||
int dcType;
|
||||
|
||||
|
@ -557,7 +556,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
dcType = 0;
|
||||
}
|
||||
|
||||
builder.addRadioItem("OFFICAL", dcType == 0, (cell) -> {
|
||||
builder.addRadioItem(LocaleController.getString("CustomBackendProduction",R.string.CustomBackendProduction), dcType == 0, (cell) -> {
|
||||
|
||||
targetDc.set(0);
|
||||
|
||||
|
@ -569,7 +568,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
});
|
||||
|
||||
builder.addRadioItem("TEST DC", dcType == 1, (cell) -> {
|
||||
builder.addRadioItem(LocaleController.getString("CustomBackendTestDC",R.string.CustomBackendTestDC), dcType == 1, (cell) -> {
|
||||
|
||||
targetDc.set(1);
|
||||
|
||||
|
@ -593,7 +592,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
});
|
||||
|
||||
inputs[0] = builder.addEditText("Ipv4 Address");
|
||||
inputs[0] = builder.addEditText(LocaleController.getString("CustomBackendIpv4",R.string.CustomBackendIpv4));
|
||||
inputs[0].setFilters(new InputFilter[]{new InputFilter.LengthFilter(15)});
|
||||
if (StrUtil.isNotBlank(NekoXConfig.customDcIpv4)) {
|
||||
inputs[0].setText(NekoXConfig.customDcIpv4);
|
||||
|
@ -618,7 +617,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
}
|
||||
});
|
||||
|
||||
inputs[1] = builder.addEditText("Ipv6 Address");
|
||||
inputs[1] = builder.addEditText(LocaleController.getString("CustomBackendIpv6",R.string.CustomBackendIpv6));
|
||||
if (StrUtil.isNotBlank(NekoXConfig.customDcIpv6)) {
|
||||
inputs[1].setText(NekoXConfig.customDcIpv6);
|
||||
}
|
||||
|
@ -642,7 +641,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
}
|
||||
});
|
||||
|
||||
inputs[2] = builder.addEditText("Port");
|
||||
inputs[2] = builder.addEditText(LocaleController.getString("UseProxyPort",R.string.UseProxyPort));
|
||||
inputs[2].setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
if (NekoXConfig.customDcPort != 0) {
|
||||
inputs[2].setText(NekoXConfig.customDcPort + "");
|
||||
|
@ -673,7 +672,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
}
|
||||
});
|
||||
|
||||
inputs[3] = builder.addEditText("Layer");
|
||||
inputs[3] = builder.addEditText(LocaleController.getString("CustomBackendLayer",R.string.CustomBackendLayer));
|
||||
inputs[3].setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
if (NekoXConfig.customDcLayer != 0) {
|
||||
inputs[3].setText(NekoXConfig.customDcLayer + "");
|
||||
|
@ -704,7 +703,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
}
|
||||
});
|
||||
|
||||
inputs[4] = builder.addEditText("Public Key");
|
||||
inputs[4] = builder.addEditText(LocaleController.getString("CustomBackendPublicKey",R.string.CustomBackendPublicKey));
|
||||
inputs[4].setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
inputs[4].setGravity(Gravity.TOP | LocaleController.generateFlagStart());
|
||||
inputs[4].setSingleLine(false);
|
||||
|
@ -721,32 +720,23 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if (StrUtil.isBlank(s.toString())) {
|
||||
NekoXConfig.customDcPublicKey = "";
|
||||
inputs[5].setText("PublicKey required");
|
||||
inputs[5].setText("");
|
||||
} else {
|
||||
|
||||
try {
|
||||
|
||||
String publicKeyBase64 = s.toString()
|
||||
.replace("-----BEGIN RSA PUBLIC KEY-----", "")
|
||||
.replace("-----BEGIN PUBLIC KEY-----", "")
|
||||
.replace("-----END RSA PUBLIC KEY-----", "")
|
||||
.replace("-----END PUBLIC KEY-----", "");
|
||||
.replace("-----END RSA PUBLIC KEY-----", "");
|
||||
|
||||
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decode(publicKeyBase64)));
|
||||
PKCS1Pub.decodePKCS1PublicKey(Base64.decode(publicKeyBase64));
|
||||
|
||||
NekoXConfig.customDcPublicKey = s.toString();
|
||||
inputs[4].setError(null);
|
||||
|
||||
long fingerprint = DataCenter.calcAuthKeyId(publicKey.getEncoded());
|
||||
inputs[5].setText(Long.toHexString(fingerprint));
|
||||
NekoXConfig.customDcFingerprint = fingerprint;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
FileLog.e("Invalid public key",e);
|
||||
|
||||
inputs[4].setError("Invalid RSA Public Key");
|
||||
inputs[5].setText("PublicKey required");
|
||||
inputs[4].setError("Invalid PKCS1 Key");
|
||||
NekoXConfig.customDcPublicKey = "";
|
||||
|
||||
}
|
||||
|
@ -759,12 +749,41 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
}
|
||||
});
|
||||
|
||||
inputs[5] = builder.addEditText();
|
||||
inputs[5].setText("PublicKey required");
|
||||
inputs[5].setEnabled(false);
|
||||
inputs[5] = builder.addEditText(LocaleController.getString("CustomBackendFingerprint",R.string.CustomBackendFingerprint));
|
||||
if (NekoXConfig.customDcFingerprint != 0) {
|
||||
inputs[5].setText(NekoXConfig.customDcFingerprint + "");
|
||||
inputs[5].setText("0x" + Long.toString(NekoXConfig.customDcFingerprint,16));
|
||||
}
|
||||
inputs[5].addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if (StrUtil.isBlank(s.toString())) {
|
||||
NekoXConfig.customDcFingerprint = 0;
|
||||
inputs[5].setError(null);
|
||||
} else {
|
||||
String f = s.toString();
|
||||
int r = 10;
|
||||
if (f.startsWith("0x")) {
|
||||
f = f.substring(2);
|
||||
r = 16;
|
||||
}
|
||||
try {
|
||||
NekoXConfig.customDcFingerprint = new BigInteger(f,r).longValue();
|
||||
inputs[5].setError(null);
|
||||
} catch (NumberFormatException e) {
|
||||
NekoXConfig.customDcFingerprint = 0;
|
||||
inputs[5].setError("Invalid Fingerprint");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
|
||||
if (dcType < 2) {
|
||||
|
||||
|
@ -795,7 +814,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
} else if (StrUtil.isBlank(inputs[2].getText().toString())) {
|
||||
} else if (NekoXConfig.customDcPort == 0) {
|
||||
|
||||
AlertUtil.showToast("Input Port");
|
||||
inputs[2].setError("Port required");
|
||||
|
@ -804,7 +823,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
} else if (StrUtil.isBlank(inputs[3].getText().toString())) {
|
||||
} else if (NekoXConfig.customDcLayer == 0) {
|
||||
|
||||
AlertUtil.showToast("Input Layer");
|
||||
inputs[3].setError("Layer required");
|
||||
|
@ -813,7 +832,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
} else if (StrUtil.isBlank(inputs[4].getText().toString())) {
|
||||
} else if (StrUtil.isBlank(NekoXConfig.customDcPublicKey)) {
|
||||
|
||||
AlertUtil.showToast("Input PublicKey");
|
||||
inputs[4].setError("PublicKey required");
|
||||
|
@ -822,6 +841,15 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
} else if (NekoXConfig.customDcFingerprint == 0L) {
|
||||
|
||||
AlertUtil.showToast("Input Fingerprint");
|
||||
inputs[5].setError("Fingerprint required");
|
||||
inputs[5].requestFocus();
|
||||
AndroidUtilities.showKeyboard(inputs[5]);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
} else if (StrUtil.isBlank(NekoXConfig.customDcIpv4) && StrUtil.isBlank(NekoXConfig.customDcIpv6)) {
|
||||
|
||||
AlertUtil.showToast("Input Address");
|
||||
|
|
|
@ -1,24 +1,29 @@
|
|||
package tw.nekomimi.nekogram
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil
|
||||
import cn.hutool.crypto.digest.DigestUtil
|
||||
import org.telegram.messenger.MessagesController
|
||||
import org.telegram.tgnet.ConnectionsManager
|
||||
import org.telegram.tgnet.SerializedData
|
||||
import java.math.BigInteger
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.interfaces.RSAPublicKey
|
||||
|
||||
object DataCenter {
|
||||
|
||||
// func calcAuthKeyId(keyData []byte) int64 {
|
||||
// sha1 := Sha1Digest(keyData)
|
||||
// // Lower 64 bits = 8 bytes of 20 byte SHA1 hash.
|
||||
// return int64(binary.LittleEndian.Uint64(sha1[12:]))
|
||||
// }
|
||||
// sha1 := Sha1Digest(keyData)
|
||||
// // Lower 64 bits = 8 bytes of 20 byte SHA1 hash.
|
||||
// return int64(binary.LittleEndian.Uint64(sha1[12:]))
|
||||
// }
|
||||
@JvmStatic
|
||||
fun calcAuthKeyId(publicKey: ByteArray): Long {
|
||||
fun calcAuthKeyId(publicKey: RSAPublicKey): Long {
|
||||
|
||||
val sha1 = DigestUtil.sha1(publicKey)
|
||||
val key = SerializedData()
|
||||
|
||||
return ByteBuffer.wrap(ArrayUtil.sub(sha1, 12, sha1.size)).long
|
||||
key.writeByteArray(publicKey.modulus.toByteArray())
|
||||
key.writeByteArray(publicKey.publicExponent.toByteArray())
|
||||
|
||||
return BigInteger(DigestUtil.sha1(key.toByteArray()).slice(12 until 20).toByteArray()).toLong()
|
||||
|
||||
}
|
||||
|
||||
|
@ -80,7 +85,7 @@ object DataCenter {
|
|||
}
|
||||
|
||||
ConnectionsManager.native_saveDatacenters(account)
|
||||
ConnectionsManager.native_setLayer(account,layer)
|
||||
ConnectionsManager.native_setLayer(account, layer)
|
||||
|
||||
repeat(5) {
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
|||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Environment;
|
||||
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
|
|
|
@ -644,7 +644,7 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
disablePhotoSideActionRow = rowCount++;
|
||||
hideKeyboardOnChatScrollRow = rowCount++;
|
||||
rearVideoMessagesRow = rowCount++;
|
||||
hideAllTabRow = NekoXConfig.developerMode ? rowCount++ : -1;
|
||||
hideAllTabRow = rowCount ++;
|
||||
mapPreviewRow = rowCount++;
|
||||
stickerSizeRow = rowCount++;
|
||||
messageMenuRow = rowCount++;
|
||||
|
|
|
@ -87,7 +87,7 @@ public class NekoXConfig {
|
|||
|
||||
public static String customDcIpv4 = preferences.getString("custom_dc_v4", "");
|
||||
public static String customDcIpv6 = preferences.getString("custom_dc_v6", "");
|
||||
public static int customDcPort = preferences.getInt("custom_dc_port", 12345);
|
||||
public static int customDcPort = preferences.getInt("custom_dc_port", 0);
|
||||
public static int customDcLayer = preferences.getInt("custom_dc_layer", 0);
|
||||
|
||||
public static String customDcPublicKey = preferences.getString("custom_dc_public_key", "");
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package tw.nekomimi.nekogram.parts;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
public class PKCS1Pub {
|
||||
|
||||
private static final int SEQUENCE_TAG = 0x30;
|
||||
private static final int BIT_STRING_TAG = 0x03;
|
||||
private static final byte[] NO_UNUSED_BITS = new byte[] { 0x00 };
|
||||
private static final byte[] RSA_ALGORITHM_IDENTIFIER_SEQUENCE =
|
||||
{(byte) 0x30, (byte) 0x0d,
|
||||
(byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01,
|
||||
(byte) 0x05, (byte) 0x00};
|
||||
|
||||
|
||||
public static RSAPublicKey decodePKCS1PublicKey(byte[] pkcs1PublicKeyEncoding)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException
|
||||
{
|
||||
byte[] subjectPublicKeyInfo2 = createSubjectPublicKeyInfoEncoding(pkcs1PublicKeyEncoding);
|
||||
KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKey generatePublic = (RSAPublicKey) rsaKeyFactory.generatePublic(new X509EncodedKeySpec(subjectPublicKeyInfo2));
|
||||
return generatePublic;
|
||||
}
|
||||
|
||||
public static byte[] createSubjectPublicKeyInfoEncoding(byte[] pkcs1PublicKeyEncoding)
|
||||
{
|
||||
byte[] subjectPublicKeyBitString = createDEREncoding(BIT_STRING_TAG, concat(NO_UNUSED_BITS, pkcs1PublicKeyEncoding));
|
||||
byte[] subjectPublicKeyInfoValue = concat(RSA_ALGORITHM_IDENTIFIER_SEQUENCE, subjectPublicKeyBitString);
|
||||
byte[] subjectPublicKeyInfoSequence = createDEREncoding(SEQUENCE_TAG, subjectPublicKeyInfoValue);
|
||||
|
||||
return subjectPublicKeyInfoSequence;
|
||||
}
|
||||
|
||||
private static byte[] concat(byte[] ... bas)
|
||||
{
|
||||
int len = 0;
|
||||
for (int i = 0; i < bas.length; i++)
|
||||
{
|
||||
len += bas[i].length;
|
||||
}
|
||||
|
||||
byte[] buf = new byte[len];
|
||||
int off = 0;
|
||||
for (int i = 0; i < bas.length; i++)
|
||||
{
|
||||
System.arraycopy(bas[i], 0, buf, off, bas[i].length);
|
||||
off += bas[i].length;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static byte[] createDEREncoding(int tag, byte[] value)
|
||||
{
|
||||
if (tag < 0 || tag >= 0xFF)
|
||||
{
|
||||
throw new IllegalArgumentException("Currently only single byte tags supported");
|
||||
}
|
||||
|
||||
byte[] lengthEncoding = createDERLengthEncoding(value.length);
|
||||
|
||||
int size = 1 + lengthEncoding.length + value.length;
|
||||
byte[] derEncodingBuf = new byte[size];
|
||||
|
||||
int off = 0;
|
||||
derEncodingBuf[off++] = (byte) tag;
|
||||
System.arraycopy(lengthEncoding, 0, derEncodingBuf, off, lengthEncoding.length);
|
||||
off += lengthEncoding.length;
|
||||
System.arraycopy(value, 0, derEncodingBuf, off, value.length);
|
||||
|
||||
return derEncodingBuf;
|
||||
}
|
||||
|
||||
private static byte[] createDERLengthEncoding(int size)
|
||||
{
|
||||
if (size <= 0x7F)
|
||||
{
|
||||
// single byte length encoding
|
||||
return new byte[] { (byte) size };
|
||||
}
|
||||
else if (size <= 0xFF)
|
||||
{
|
||||
// double byte length encoding
|
||||
return new byte[] { (byte) 0x81, (byte) size };
|
||||
}
|
||||
else if (size <= 0xFFFF)
|
||||
{
|
||||
// triple byte length encoding
|
||||
return new byte[] { (byte) 0x82, (byte) (size >> Byte.SIZE), (byte) size };
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("size too large, only up to 64KiB length encoding supported: " + size);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.os.storage.StorageManager
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import org.telegram.messenger.FileLog
|
||||
import java.io.File
|
||||
|
||||
object EnvUtil {
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val rootDirectories by lazy {
|
||||
|
||||
val mStorageManager = ApplicationLoader.applicationContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
|
||||
(mStorageManager.javaClass.getMethod("getVolumePaths").invoke(mStorageManager) as Array<String>).map { File(it) }
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun doTest() {
|
||||
|
||||
FileLog.d("rootDirectories: ${rootDirectories.size}")
|
||||
|
||||
rootDirectories.forEach { FileLog.d(it.path) }
|
||||
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -6,10 +6,20 @@
|
|||
<string name="CustomApi">Custom API</string>
|
||||
<string name="UseCustomApiNotice">Log in using the custom api, if you are unable to register or log in, this may help.\n\nNote: fcm will not work if you are using the release version.</string>
|
||||
<string name="CustomApiNo">Don\'t use custom API</string>
|
||||
<string name="CustomApiOffical">Telegram Android</string>
|
||||
<string name="CustomApiOfficial">Telegram Android</string>
|
||||
<string name="CustomApiTGX">Telegram Android X</string>
|
||||
<string name="CustomApiInput">Manual input</string>
|
||||
|
||||
<string name="CustomBackend">Custom Backend</string>
|
||||
<string name="CustomBackendNotice">This function is only provided for expert users, if you don\'t know what the following options represent, just ignore it.</string>
|
||||
<string name="CustomBackendProduction">Official Production DataCenter</string>
|
||||
<string name="CustomBackendTestDC">Official Test DataCenter</string>
|
||||
<string name="CustomBackendIpv4">Ipv4 Address</string>
|
||||
<string name="CustomBackendIpv6">Ipv6 Address</string>
|
||||
<string name="CustomBackendLayer">Layer</string>
|
||||
<string name="CustomBackendPublicKey">Public Key</string>
|
||||
<string name="CustomBackendFingerprint">Key Fingerprint</string>
|
||||
|
||||
<string name="AllowFlashCall">Allow flash call</string>
|
||||
|
||||
<string name="ChangeTranslateProvider">Change Provider</string>
|
||||
|
|
Loading…
Reference in New Issue