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.
245 lines (216 loc) • 8.42 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 { MalwarelyticsModule, MalwarelyticsModuleIfc, wrapNativeCall } from "./internal/MalwarelyticsModule";
import { EventHelper } from "./internal/EventHelper";
import type { MalwarelyticsConfig } from "./MalwarelyticsConfig";
import { MalwarelyticsRasp } from "./MalwarelyticsRasp";
import { MalwarelyticsAntivirus } from "./MalwarelyticsAntivirus";
import { MalwarelyticsAppleDetectableApp } from "./MalwarelyticsConfig";
import { Platform } from "react-native";
import { MalwarelyticsError } from "./MalwarelyticsError";
/**
* JavaScript wrapper around native kotlin/swift Malwarelytics code.
*/
export class Malwarelytics {
// Shared instance
/**
* Contains shared instance of Malwarelytics class.
*/
static get sharedInstance(): Malwarelytics {
if (this.instance === undefined) {
this.instance = new Malwarelytics()
}
return this.instance
}
// Configuration
/**
* Get state of the Malwarelytics module.
*
* This function also updates content of `initializationResult` getter, if result
* is available.
*
* @returns State of the module.
*/
getState(): Promise<MalwarelyticsState> {
return this.withModule(async (module) => {
const stateWithResult = await module.getState()
this.lastInitializationResult = stateWithResult.result
return stateWithResult.state
})
}
/**
* Apple specific: Obtain list of DetectableApp.KnownApp items that are predefined in native iOS library.
*
* @returns List of DetectableApp.KnownApp items.
*/
getKnownDetectableApps(): Promise<MalwarelyticsAppleDetectableApp[]> {
if (Platform.OS != "ios") {
return Promise.reject(new MalwarelyticsError("METHOD_NOT_SUPPORTED", "This method is supported only on Apple platforms"))
}
return this.withModule(module => module.getKnownDetectableApps())
}
/**
* Initialize Malwarelytics instance with given configuration.
*
* Note that if you want to change the configuration on the running instance,
* then you have to `shutdown()` the instance first.
*
* @param configuration Configuration to apply.
*/
initialize(configuration: MalwarelyticsConfig): Promise<MalwarelyticsInitializationResult> {
return this.withModule(async (module) => {
this.lastInitializationResult = await module.initialize(configuration)
return this.lastInitializationResult
})
}
/**
* Contains information about last initialization result.
*/
get initializationResult(): MalwarelyticsInitializationResult | undefined {
return this.lastInitializationResult
}
/**
* Shutdown the previously initialized Malwarelytics instance.
* @param clearAvUserId If `true`, then clears also persistent AV user ID, making the device appear as a newly created. The default value is `false`.
*/
shutdown(clearAvUserId: boolean = false): Promise<void> {
return this.withModule(async (module) => {
await module.shutdown(clearAvUserId)
this.lastInitializationResult = undefined
})
}
/**
* Get information whether module is already initialized.
*/
async isInitialized(): Promise<boolean> {
return (await this.getState()) == "READY"
}
/**
* Sets new client id that will be sent to the backend for user identification.
* Pass `undefined` to remove the current client id (for example when user logged-out).
*
* @param clientId Client id, `undefied` for deleting the value
*/
setClientId(clientId: string | undefined): Promise<void> {
return this.withModule((module) => module.setClientId(clientId))
}
/**
* Sets new device id that will be sent to the backend for user identification.
* Pass `undefied` to remove the current device id.
*
* @param deviceId Device id, `undefied` for deleting the value
*/
setDeviceId(deviceId: string | undefined): Promise<void> {
return this.withModule((module) => module.setDeviceId(deviceId))
}
/**
* Get AV User ID if it is available. The AV User ID will be available if the SDK initialized with
* result `SUCCESS`. Otherwise it might be undefined.
*/
getAvUserId(): Promise<string | undefined> {
return this.withModule(module => module.getAvUserId())
}
// Events
/**
* Object representing a subscription to state events.
*/
private stateEventsSubscription: EmitterSubscription | undefined
/**
* Set listener for Malwarelytic's instance state changes.
* @param listener Listener implementation.
*/
async setStateListener(listener: MalwarelyticsStateListener): Promise<void> {
this.stateEventsSubscription?.remove()
this.stateEventsSubscription = await this.eventHelper.addListener('Malwarelytics.STATE', (data) => {
listener.malwarelyticsStateChanged(data as MalwarelyticsState)
})
}
/**
* Remove state listener previously set by `setStateListener()` method.
*/
removeStateListener() {
this.stateEventsSubscription?.remove()
this.stateEventsSubscription = undefined
}
// Private methods and properties
/**
* Instance of native module.
*/
private readonly nativeModule: MalwarelyticsModuleIfc
/**
* Instance of event helper.
*/
private readonly eventHelper: EventHelper
/**
* RASP module
*/
readonly rasp: MalwarelyticsRasp
/**
* Antivirus module
*/
readonly antivirus: MalwarelyticsAntivirus
/**
* Shared instnace of this class.
*/
private static instance: Malwarelytics | undefined
/**
* Last initialization result
*/
private lastInitializationResult: MalwarelyticsInitializationResult | undefined
/**
* Private constructor.
*/
private constructor() {
this.nativeModule = MalwarelyticsModule
this.eventHelper = new EventHelper(this.nativeModule)
this.rasp = new MalwarelyticsRasp(this.eventHelper)
this.antivirus = new MalwarelyticsAntivirus(this.eventHelper)
}
/**
* Execute closure with action with properly acquired instnace to native module.
* @param action Action to execute.
* @returns Result returned from the action.
*/
private async withModule<T>(action: (nativeModule: MalwarelyticsModuleIfc) => Promise<T>): Promise<T> {
return wrapNativeCall(this.nativeModule, action)
}
}
/**
* Type defining the state of Malwarelytics module:
* - `"SHUTDOWN"` - Malwarelytics is not initialized.
* - `"PENDING_INIT"` - Malwarelytics is initializing.
* - `"READY"` - Malwarelytics is ready and prepared for use.
* - `"PENDING_SHUTDOWN"` - Malwarelytics is shutting down.
*/
export type MalwarelyticsState = 'SHUTDOWN' | 'PENDING_INIT' | 'READY' | 'PENDING_SHUTDOWN';
/**
* Type defining the result of Malwarelytics initialization.
* - `'SUCCESS'` - Initialization completed successfully
* - `'PERMANENT_OFFLINE_MODE'` - SDK works in permanent offline mode.
* - `'TEMPORARY_OFFLINE_MODE'` - Android only: SDK works in temporary offline mode.
*/
export type MalwarelyticsInitializationResult = 'SUCCESS' | 'TEMPORARY_OFFLINE_MODE' | 'PERMANENT_OFFLINE_MODE';
/**
* Interface for listening Malwarelytics module state changes.
*/
export interface MalwarelyticsStateListener {
/**
* Called when state of Malwarelytics module is changed.
* @param state New module's state.
*/
malwarelyticsStateChanged(state: MalwarelyticsState): void;
}