mirror of
https://github.com/kdrag0n/safetynet-fix.git
synced 2024-10-06 06:39:49 +00:00
riru: Initial module implementation
This commit is contained in:
parent
1282960dbf
commit
8d50d8fe3c
@ -4,12 +4,12 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk 31
|
compileSdk 30
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "dev.kdrag0n.safetynetriru"
|
applicationId "dev.kdrag0n.safetynetriru"
|
||||||
minSdk 24
|
minSdk 24
|
||||||
targetSdk 31
|
targetSdk 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
|
||||||
|
27
java_module/app/proguard-rules.pro
vendored
27
java_module/app/proguard-rules.pro
vendored
@ -27,3 +27,30 @@
|
|||||||
-keepclassmembers class dev.kdrag0n.safetynetriru.proxy.ProxyKeyStoreSpi {
|
-keepclassmembers class dev.kdrag0n.safetynetriru.proxy.ProxyKeyStoreSpi {
|
||||||
public <init>(...);
|
public <init>(...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Remove @DebugMetadata annotations to avoid leaking info
|
||||||
|
# Source: https://proandroiddev.com/kotlin-cleaning-java-bytecode-before-release-9567d4c63911
|
||||||
|
-checkdiscard @interface kotlin.coroutines.jvm.internal.DebugMetadata
|
||||||
|
-assumenosideeffects public class kotlin.coroutines.jvm.internal.BaseContinuationImpl {
|
||||||
|
private kotlin.coroutines.jvm.internal.DebugMetadata getDebugMetadataAnnotation() return null;
|
||||||
|
public java.lang.StackTraceElement getStackTraceElement() return null;
|
||||||
|
public java.lang.String[] getSpilledVariableFieldMapping() return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||||
|
# Remove verbose NPE intrinsics to reduce code size and avoid leaking info
|
||||||
|
# Source: https://issuetracker.google.com/issues/190489514
|
||||||
|
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
|
||||||
|
static void checkNotNullParameter(java.lang.Object, java.lang.String);
|
||||||
|
static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
|
||||||
|
static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
|
||||||
|
static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
|
||||||
|
static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
|
||||||
|
static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
|
||||||
|
static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
|
||||||
|
static void checkNotNull(java.lang.Object);
|
||||||
|
static void checkNotNull(java.lang.Object, java.lang.String);
|
||||||
|
|
||||||
|
# Remove remaining stray calls to stringPlus
|
||||||
|
static java.lang.String stringPlus(java.lang.String, java.lang.Object);
|
||||||
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
ext {
|
|
||||||
/*
|
|
||||||
This name will be used in the name of the so file ("lib${moduleLibraryName}.so").
|
|
||||||
*/
|
|
||||||
moduleLibraryName = "template"
|
|
||||||
|
|
||||||
/* Minimal supported Riru API version, used in the version check of riru.sh */
|
|
||||||
moduleMinRiruApiVersion = 24
|
|
||||||
|
|
||||||
/* The version name of minimal supported Riru, used in the version check of riru.sh */
|
|
||||||
moduleMinRiruVersionName = "v24.0.0"
|
|
||||||
|
|
||||||
/* Maximum supported Riru API version, used in the version check of riru.sh */
|
|
||||||
moduleRiruApiVersion = 26
|
|
||||||
|
|
||||||
/*
|
|
||||||
Magisk module ID
|
|
||||||
Since Magisk use it to distinguish different modules, you should never change it.
|
|
||||||
|
|
||||||
Note, the older version of the template uses '-' instead of '_', if your are upgrading from
|
|
||||||
the older version, please pay attention.
|
|
||||||
*/
|
|
||||||
magiskModuleId = "riru_template"
|
|
||||||
|
|
||||||
moduleName = "Template"
|
|
||||||
moduleAuthor = "Template"
|
|
||||||
moduleDescription = "Riru module template. Requires Riru $moduleMinRiruVersionName or above."
|
|
||||||
moduleVersion = "v26.0.0"
|
|
||||||
moduleVersionCode = 26
|
|
||||||
}
|
|
@ -4,6 +4,115 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define DEBUG(...) __android_log_write(ANDROID_LOG_DEBUG, "SafetyNetJNI/SARU", __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DEBUG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr bool DEBUG = true;
|
||||||
|
|
||||||
|
static void *moduleDex;
|
||||||
|
static size_t moduleDexSize;
|
||||||
|
|
||||||
|
static constexpr size_t APP_DATA_DIR_SIZE = 128;
|
||||||
|
static char lastAppDataDir[APP_DATA_DIR_SIZE];
|
||||||
|
|
||||||
|
static void updateAppDataDir(JNIEnv *env, jstring appDataDir) {
|
||||||
|
DEBUG("updateAppDataDir");
|
||||||
|
if (appDataDir == nullptr) {
|
||||||
|
DEBUG("dir is null");
|
||||||
|
memset(lastAppDataDir, 0, APP_DATA_DIR_SIZE);
|
||||||
|
} else {
|
||||||
|
DEBUG("copy dir");
|
||||||
|
const char *copy = env->GetStringUTFChars(appDataDir, NULL);
|
||||||
|
strncpy(lastAppDataDir, copy, APP_DATA_DIR_SIZE);
|
||||||
|
env->ReleaseStringUTFChars(appDataDir, copy);
|
||||||
|
DEBUG(lastAppDataDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void specializeCommon(JNIEnv *env) {
|
||||||
|
DEBUG("specializeCommon");
|
||||||
|
DEBUG(lastAppDataDir);
|
||||||
|
if (moduleDex == nullptr) {
|
||||||
|
DEBUG("dex null");
|
||||||
|
}
|
||||||
|
if (moduleDex == nullptr || strstr(lastAppDataDir, "com.google.android.gms") == nullptr) {
|
||||||
|
DEBUG("pkg doesn't match");
|
||||||
|
riru_set_unload_allowed(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("get system classloader");
|
||||||
|
// First, get the system classloader
|
||||||
|
jclass clClass = env->FindClass("java/lang/ClassLoader");
|
||||||
|
jmethodID getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||||
|
jobject systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
||||||
|
|
||||||
|
DEBUG("create buf");
|
||||||
|
// Assuming we have a valid mapped module, load it. This is similar to the approach used for
|
||||||
|
// Dynamite modules in GmsCompat, except we can use InMemoryDexClassLoader directly instead of
|
||||||
|
// tampering with DelegateLastClassLoader's DexPathList.
|
||||||
|
jobject buf = env->NewDirectByteBuffer(moduleDex, moduleDexSize);
|
||||||
|
DEBUG("construct dex cl");
|
||||||
|
jclass dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
|
||||||
|
jmethodID dexClInit = env->GetMethodID(dexClClass, "<init>", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||||
|
jobject dexCl = env->NewObject(dexClClass, dexClInit, buf, systemClassLoader);
|
||||||
|
|
||||||
|
// Run it
|
||||||
|
DEBUG("load class method lookup");
|
||||||
|
jmethodID loadClass = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
|
DEBUG("call load class");
|
||||||
|
// Create a Java string. VM crashes with a C string.
|
||||||
|
jstring entryClassName = env->NewStringUTF("dev.kdrag0n.safetynetriru.EntryPoint");
|
||||||
|
jobject entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName);
|
||||||
|
|
||||||
|
// Call init
|
||||||
|
DEBUG("call init");
|
||||||
|
auto entryClass = (jclass) entryClassObj;
|
||||||
|
jmethodID entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
|
||||||
|
env->CallStaticVoidMethod(entryClass, entryInit);
|
||||||
|
DEBUG("specializeCommon end");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *readFile(char *path, size_t *fileSize) {
|
||||||
|
int fd = open(path, O_RDONLY, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
DEBUG("open fail");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// Get size
|
||||||
|
DEBUG("get size");
|
||||||
|
*fileSize = lseek(fd, 0, SEEK_END);
|
||||||
|
if (*fileSize < 0) {
|
||||||
|
DEBUG("seek fail");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
// Map
|
||||||
|
/*
|
||||||
|
DEBUG("mmap");
|
||||||
|
moduleDex = mmap(nullptr, *fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
if (moduleDex == MAP_FAILED) {
|
||||||
|
DEBUG("mmap fail");
|
||||||
|
}*/
|
||||||
|
// Close the fd. This doesn't destroy the mapping.
|
||||||
|
//DEBUG("close");
|
||||||
|
char *data = (char *) malloc(*fileSize);
|
||||||
|
int bytes = 0;
|
||||||
|
while (bytes < *fileSize) {
|
||||||
|
bytes += read(fd, data + bytes, *fileSize - bytes);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static void forkAndSpecializePre(
|
static void forkAndSpecializePre(
|
||||||
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
|
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
|
||||||
@ -11,25 +120,7 @@ static void forkAndSpecializePre(
|
|||||||
jintArray *fdsToClose, jintArray *fdsToIgnore, jboolean *is_child_zygote,
|
jintArray *fdsToClose, jintArray *fdsToIgnore, jboolean *is_child_zygote,
|
||||||
jstring *instructionSet, jstring *appDataDir, jboolean *isTopApp, jobjectArray *pkgDataInfoList,
|
jstring *instructionSet, jstring *appDataDir, jboolean *isTopApp, jobjectArray *pkgDataInfoList,
|
||||||
jobjectArray *whitelistedDataInfoList, jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
|
jobjectArray *whitelistedDataInfoList, jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
|
||||||
// Called "before" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
updateAppDataDir(env, *appDataDir);
|
||||||
// Parameters are pointers, you can change the value of them if you want
|
|
||||||
// Some parameters are not exist is older Android versions, in this case, they are null or 0
|
|
||||||
}
|
|
||||||
|
|
||||||
static void forkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
|
|
||||||
// Called "after" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
|
||||||
// "res" is the return value of com_android_internal_os_Zygote_nativeForkAndSpecialize
|
|
||||||
|
|
||||||
if (res == 0) {
|
|
||||||
// In app process
|
|
||||||
|
|
||||||
// When unload allowed is true, the module will be unloaded (dlclose) by Riru
|
|
||||||
// If this modules has hooks installed, DONOT set it to true, or there will be SIGSEGV
|
|
||||||
// This value will be automatically reset to false before the "pre" function is called
|
|
||||||
riru_set_unload_allowed(true);
|
|
||||||
} else {
|
|
||||||
// In zygote process
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void specializeAppProcessPre(
|
static void specializeAppProcessPre(
|
||||||
@ -38,37 +129,23 @@ static void specializeAppProcessPre(
|
|||||||
jboolean *startChildZygote, jstring *instructionSet, jstring *appDataDir,
|
jboolean *startChildZygote, jstring *instructionSet, jstring *appDataDir,
|
||||||
jboolean *isTopApp, jobjectArray *pkgDataInfoList, jobjectArray *whitelistedDataInfoList,
|
jboolean *isTopApp, jobjectArray *pkgDataInfoList, jobjectArray *whitelistedDataInfoList,
|
||||||
jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
|
jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
|
||||||
// Called "before" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
updateAppDataDir(env, *appDataDir);
|
||||||
// Parameters are pointers, you can change the value of them if you want
|
}
|
||||||
// Some parameters are not exist is older Android versions, in this case, they are null or 0
|
|
||||||
|
static void forkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
|
||||||
|
// Called "after" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||||
|
// "res" is the return value of com_android_internal_os_Zygote_nativeForkAndSpecialize
|
||||||
|
|
||||||
|
if (res == 0) {
|
||||||
|
// In app process
|
||||||
|
specializeCommon(env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void specializeAppProcessPost(
|
static void specializeAppProcessPost(
|
||||||
JNIEnv *env, jclass clazz) {
|
JNIEnv *env, jclass clazz) {
|
||||||
// Called "after" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
// Called "after" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||||
|
specializeCommon(env);
|
||||||
// When unload allowed is true, the module will be unloaded (dlclose) by Riru
|
|
||||||
// If this modules has hooks installed, DONOT set it to true, or there will be SIGSEGV
|
|
||||||
// This value will be automatically reset to false before the "pre" function is called
|
|
||||||
riru_set_unload_allowed(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void forkSystemServerPre(
|
|
||||||
JNIEnv *env, jclass clazz, uid_t *uid, gid_t *gid, jintArray *gids, jint *runtimeFlags,
|
|
||||||
jobjectArray *rlimits, jlong *permittedCapabilities, jlong *effectiveCapabilities) {
|
|
||||||
// Called "before" com_android_internal_os_Zygote_forkSystemServer in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
|
||||||
// Parameters are pointers, you can change the value of them if you want
|
|
||||||
// Some parameters are not exist is older Android versions, in this case, they are null or 0
|
|
||||||
}
|
|
||||||
|
|
||||||
static void forkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
|
|
||||||
// Called "after" com_android_internal_os_Zygote_forkSystemServer in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
|
||||||
|
|
||||||
if (res == 0) {
|
|
||||||
// In system server process
|
|
||||||
} else {
|
|
||||||
// In zygote process
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onModuleLoaded() {
|
static void onModuleLoaded() {
|
||||||
@ -77,6 +154,21 @@ static void onModuleLoaded() {
|
|||||||
// If you want to use threads, start them here rather than the constructors
|
// If you want to use threads, start them here rather than the constructors
|
||||||
// __attribute__((constructor)) or constructors of static variables,
|
// __attribute__((constructor)) or constructors of static variables,
|
||||||
// or the "hide" will cause SIGSEGV
|
// or the "hide" will cause SIGSEGV
|
||||||
|
|
||||||
|
|
||||||
|
// Load
|
||||||
|
DEBUG("onModuleLoaded, loading file");
|
||||||
|
char pathBuf[128];
|
||||||
|
snprintf(pathBuf, 128, "%s/%s", riru_magisk_module_path, "classes.dex");
|
||||||
|
DEBUG((char*)riru_magisk_module_path);
|
||||||
|
DEBUG(pathBuf);
|
||||||
|
|
||||||
|
moduleDex = readFile(pathBuf, &moduleDexSize);
|
||||||
|
if (!moduleDex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("module loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -86,19 +178,19 @@ const char *riru_magisk_module_path = nullptr;
|
|||||||
int *riru_allow_unload = nullptr;
|
int *riru_allow_unload = nullptr;
|
||||||
|
|
||||||
static auto module = RiruVersionedModuleInfo{
|
static auto module = RiruVersionedModuleInfo{
|
||||||
.moduleApiVersion = riru::moduleApiVersion,
|
.moduleApiVersion = riru::moduleApiVersion,
|
||||||
.moduleInfo= RiruModuleInfo{
|
.moduleInfo = RiruModuleInfo{
|
||||||
.supportHide = true,
|
.supportHide = true,
|
||||||
.version = riru::moduleVersionCode,
|
.version = riru::moduleVersionCode,
|
||||||
.versionName = riru::moduleVersionName,
|
.versionName = riru::moduleVersionName,
|
||||||
.onModuleLoaded = onModuleLoaded,
|
.onModuleLoaded = onModuleLoaded,
|
||||||
.forkAndSpecializePre = forkAndSpecializePre,
|
.forkAndSpecializePre = forkAndSpecializePre,
|
||||||
.forkAndSpecializePost = forkAndSpecializePost,
|
.forkAndSpecializePost = forkAndSpecializePost,
|
||||||
.forkSystemServerPre = forkSystemServerPre,
|
.forkSystemServerPre = NULL,
|
||||||
.forkSystemServerPost = forkSystemServerPost,
|
.forkSystemServerPost = NULL,
|
||||||
.specializeAppProcessPre = specializeAppProcessPre,
|
.specializeAppProcessPre = specializeAppProcessPre,
|
||||||
.specializeAppProcessPost = specializeAppProcessPost
|
.specializeAppProcessPost = specializeAppProcessPost,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
RiruVersionedModuleInfo *init(Riru *riru) {
|
RiruVersionedModuleInfo *init(Riru *riru) {
|
||||||
|
21
riru/template/magisk_module/LICENSE
Normal file
21
riru/template/magisk_module/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2021 Danny Lin <danny@kdrag0n.dev>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -1 +0,0 @@
|
|||||||
# Riru - Template
|
|
@ -1,7 +1,6 @@
|
|||||||
SKIPUNZIP=1
|
SKIPUNZIP=1
|
||||||
|
|
||||||
# Extract verify.sh
|
# Extract verify.sh
|
||||||
ui_print "- Extracting verify.sh"
|
|
||||||
unzip -o "$ZIPFILE" 'verify.sh' -d "$TMPDIR" >&2
|
unzip -o "$ZIPFILE" 'verify.sh' -d "$TMPDIR" >&2
|
||||||
if [ ! -f "$TMPDIR/verify.sh" ]; then
|
if [ ! -f "$TMPDIR/verify.sh" ]; then
|
||||||
ui_print "*********************************************************"
|
ui_print "*********************************************************"
|
||||||
@ -38,7 +37,7 @@ fi
|
|||||||
ui_print "- Extracting module files"
|
ui_print "- Extracting module files"
|
||||||
|
|
||||||
extract "$ZIPFILE" 'module.prop' "$MODPATH"
|
extract "$ZIPFILE" 'module.prop' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'uninstall.sh' "$MODPATH"
|
extract "$ZIPFILE" 'classes.dex' "$MODPATH"
|
||||||
|
|
||||||
# Riru v24+ load files from the "riru" folder in the Magisk module folder
|
# Riru v24+ load files from the "riru" folder in the Magisk module folder
|
||||||
# This "riru" folder is also used to determine if a Magisk module is a Riru module
|
# This "riru" folder is also used to determine if a Magisk module is a Riru module
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
#!/sbin/sh
|
|
||||||
MODDIR=${0%/*}
|
|
@ -35,5 +35,4 @@ extract() {
|
|||||||
[ -f "$hash_path" ] || abort_verify "$file.sha256sum not exists"
|
[ -f "$hash_path" ] || abort_verify "$file.sha256sum not exists"
|
||||||
|
|
||||||
(echo "$(cat "$hash_path") $file_path" | sha256sum -c -s -) || abort_verify "Failed to verify $file"
|
(echo "$(cat "$hash_path") $file_path" | sha256sum -c -s -) || abort_verify "Failed to verify $file"
|
||||||
ui_print "- Verified $file" >&1
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user