react-native-malwarelytics
Version:
Malwarelytics for React Native protects your banking or fintech app from a broad range of mobile security threats with an industry-leading mobile threat intelligence solution.
248 lines (225 loc) • 9.99 kB
text/typescript
//
// Copyright 2023 Wultra s.r.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions
// and limitations under the License.
//
import type { EmitterSubscription } from "react-native";
import { Platform } from "react-native"
import { EventHelper } from "./internal/EventHelper"
import { MalwarelyticsModuleIfc, wrapNativeCall } from "./internal/MalwarelyticsModule"
import { MalwarelyticsError } from "./MalwarelyticsError"
import { SmartProtectionResult } from "./model/antivirus/SmartProtectionResult"
import { ApkThreat, ThreatIndex, threatIndexToNumber } from "./model/antivirus/ApkThreat"
import { ApkInfo } from "./model/antivirus/Apk"
import { ApkThreatEvent } from "./internal/ApkThreatEvent"
import { ObservedUpdateInfo } from "./model/antivirus/update/ObservedUpdateInfo"
import { UpdateInfo } from "./model/antivirus/update/UpdateInfo"
/**
* The `MalwarelyticsAntivirus` class provides antivirus functionality from Malwarelytics for Android SDK.
* Be aware that you must evaluate whether the funcionality is supported on the platform, by getting
* `isSupported` property. All other methods from the class fails with error if antivirus is not supported
* on the platform.
*/
export class MalwarelyticsAntivirus {
constructor(eventHelper: EventHelper) {
if (Platform.OS == 'android') {
this.module = eventHelper.module
}
this.eventHelper = eventHelper
this.isSupported = this.module != undefined
}
/**
* Determine whether the Antivirus module is supported on the platform.
*/
readonly isSupported: boolean
/**
* Instance of EventHelper shared with Malwarelytics class.
*/
private readonly eventHelper: EventHelper
/**
* Instance of native module interface.
*/
private readonly module?: MalwarelyticsModuleIfc
/**
* Object representing a subscription to update events.
*/
private updateEventSubscription: EmitterSubscription | undefined
/**
* Object representing a subscription to apk threat events.
*/
private apkThreatEventSubscription: EmitterSubscription | undefined
/**
* Test whether antivirus is enabled.
*/
isEnabled(): Promise<boolean> {
return this.withModule(module => module.isAntivirusEnabled())
}
/**
* Set custom localization to be used when a UI is shown.
* This overrides system settings. Use ISO 639-1 language code or `undefined`.
* Undefined value will reset the custom setting and the system settings will be used again
*/
setCustomLocalization(languageCode: string | undefined): Promise<void> {
return this.withModule(module => module.setAntivirusLocalization(languageCode))
}
/**
* Get custom localization currently in use by antivirus.
*/
getCustomLocalization(): Promise<string | undefined> {
return this.withModule(module => module.getAntivirusLocalization())
}
/**
* Schedules a job that will execute smart protection run. Note that this is asynchronous and
* can take some time.
*
* Note that you can call this function with multiple times, but you'll get the result once the internal
* evaluation is finished.
*
* @param performOnlineUpdate Optional argument to indicate that online update is not desired. If false only local data will be used.
*/
triggerSmartProtection(performOnlineUpdate: boolean = true): Promise<SmartProtectionResult> {
return this.withModule(module => module.triggerSmartProtection(performOnlineUpdate))
}
/**
* Get information whether smart protection evaluation is already running.
*/
isSmartProtectionTriggered(): Promise<boolean> {
return this.withModule(module => module.isSmartProtectionTriggered())
}
/**
* Returns list of all applications with the malware evaluation.
*/
getThreatList(): Promise<ApkThreat[]> {
return this.withModule(module => module.getThreatList())
}
/**
* Returns list of all applications with the malware evaluation higher or equal than specified.
* @param minThreatIndex Minimal threat index.
* @returns List of all applications with the malware evaluation higher or equal than specified.
*/
async getFilteredThreatList(minThreatIndex: ThreatIndex): Promise<ApkThreat[]> {
const minIndex = threatIndexToNumber(minThreatIndex)
return (await this.getThreatList()).filter(item => threatIndexToNumber(item.threatIndex) >= minIndex)
}
/**
* Gets more information for the package name of the application.
*
* @param packageName Package name of the application
* @returns Information about package or `undefined` when no such information is available.
*/
getApkInfo(packageName: string): Promise<ApkInfo | undefined> {
return this.withModule(module => module.getApkInfo(packageName))
}
/**
* Get information about the last updates.
*
* Primarily intended for troubleshooting.
*
* @returns Information about latest update successes and failures.
*/
getLastUpdateInfo(): Promise<UpdateInfo> {
return this.withModule(module => module.getLastUpdateInfo());
}
/** Set listener that is triggered when a suggestion update completes. */
async setUpdateListener(listener: MalwarelyticsAndroidUpdateListener): Promise<void> {
this.updateEventSubscription?.remove()
if (this.module == undefined) {
return Promise.reject(new MalwarelyticsError('METHOD_NOT_SUPPORTED', `Method is not supported on ${Platform.OS} platform`))
}
this.updateEventSubscription = await this.eventHelper.addListener('Malwarelytics.AV_UPDATE', (data) => {
// console.log(`${Platform.OS}: AV_UPDATE event: ${JSON.stringify(data)}`)
const oui = data as ObservedUpdateInfo
listener.onSuggestionUpdated(oui)
})
}
/** Remove listener for suggestion updates. */
removeUpdateListener() {
this.updateEventSubscription?.remove()
this.updateEventSubscription = undefined
}
/** Set listener that is triggered whan an app is installed/updated/uninstall. */
async setApkThreatListener(listener: MalwarelyticsAndroidApkThreatListener): Promise<void> {
this.apkThreatEventSubscription?.remove()
if (this.module == undefined) {
return Promise.reject(new MalwarelyticsError('METHOD_NOT_SUPPORTED', `Method is not supported on ${Platform.OS} platform`))
}
this.apkThreatEventSubscription = await this.eventHelper.addListener('Malwarelytics.AV_APK_THREAT', (data) => {
// console.log(`${Platform.OS}: AV_APK_THREAT event: ${JSON.stringify(data)}`)
const event = data as ApkThreatEvent
switch (event.type) {
case "INSTALL":
listener.onInstallDetected(event.payload as ApkThreat)
break
case "UPDATE":
listener.onUpdateDetected(event.payload as ApkThreat)
break
case "UNINSTALL":
listener.onUninstallDetected(event.payload as string)
break
default:
console.warn(`${Platform.OS}: Unsupported APK THREAT event ${event.type}`)
break
}
})
}
/** Remove listgener for app installs/updates/uninstall. */
removeApkThreatListener() {
this.apkThreatEventSubscription?.remove()
this.apkThreatEventSubscription = undefined
}
/**
* Execute closure with action with properly acquired instnace to native module.
* @param action Action to execute.
* @returns Result returned from the action.
*/
private withModule<T>(action: (nativeModule: MalwarelyticsModuleIfc) => Promise<T>): Promise<T> {
if (this.module != undefined) {
return wrapNativeCall(this.module, action)
}
return Promise.reject(new MalwarelyticsError('METHOD_NOT_SUPPORTED', `Method is not supported on ${Platform.OS} platform`))
}
}
/** Listener for update results. */
export interface MalwarelyticsAndroidUpdateListener {
/**
* Called when an update was finished regardless of a success or a failure.
*
* Returned data indicated the update result:
* - Successful update:
* @see ObservedUpdateInfo.failureReason is null
* - Partially successful update:
* @see ObservedUpdateInfo.failureReason is not null
* and @see ObservedUpdateInfo.updatedApps is not empty
* - Failed update:
* and @see ObservedUpdateInfo.failureReason is not null
* and @see ObservedUpdateInfo.updatedApps is empty */
onSuggestionUpdated(observedUpdateInfo: ObservedUpdateInfo): void;
}
/** Listener for updates to the apps on the device. */
export interface MalwarelyticsAndroidApkThreatListener {
/**
* Called whan an app install is detected.
* @param apkThread The new threat.
*/
onInstallDetected(apkThreat: ApkThreat): void;
/**
* Called when an app update is detected.
* @param apkThread The changed threat.
*/
onUpdateDetected(apkThreat: ApkThreat): void;
/**
* Called when an app uninstall is detected.
* @param packageName The package name of the deleted threat.
*/
onUninstallDetected(packageName: string): void;
}