import { Data } from '../data/data' ;
import { getConversationController } from '../session/conversations' ;
import { PubKey } from '../session/types' ;
import { UserUtils } from '../session/utils' ;
const BLOCKED_NUMBERS_ID = 'blocked' ;
const BLOCKED_GROUPS_ID = 'blocked-groups' ;
// tslint:disable-next-line: no-unnecessary-class
export class BlockedNumberController {
private static loaded : boolean = false ;
private static blockedNumbers : Set < string > = new Set ( ) ;
private static blockedGroups : Set < string > = new Set ( ) ;
/ * *
* Check if a device is blocked .
*
* @param user The user .
* /
public static async isBlockedAsync ( user : string | PubKey ) : Promise < boolean > {
await this . load ( ) ;
const isOurDevice = UserUtils . isUsFromCache ( user ) ;
if ( isOurDevice ) {
return false ;
}
const pubkey = PubKey . cast ( user ) ;
return this . blockedNumbers . has ( pubkey . key ) ;
}
/ * *
* Check if a device is blocked synchronously .
* This will only check against the memory cache on if a device is blocked , it is reccomended to pass in the primary device pub key .
*
* Make sure ` load() ` has been called before this function so that the correct blocked state is returned .
*
* @param number The device .
* /
public static isBlocked ( device : string | PubKey ) : boolean {
// This function is not `async` because the old `isBlocked` function in js was also not async.
// To convert it means we'll have to re-wire all our UI components to work with async.
const stringValue = device instanceof PubKey ? device.key : device.toLowerCase ( ) ;
return this . blockedNumbers . has ( stringValue ) ;
}
/ * *
* Check if a group id is blocked .
* Make sure ` load() ` has been called before this function so that the correct blocked state is returned .
*
* @param groupId The group id .
* /
public static isGroupBlocked ( groupId : string | PubKey ) : boolean {
const stringValue = groupId instanceof PubKey ? groupId.key : groupId.toLowerCase ( ) ;
return this . blockedGroups . has ( stringValue ) ;
}
/ * *
* Block a user .
* This will only block the primary device of the user .
*
* @param user The user to block .
* /
public static async block ( user : string | PubKey ) : Promise < void > {
// The reason we add all linked device to block number set instead of checking if any device of a user is in the `isBlocked` function because
// `isBlocked` is used synchronously in the code. To check if any device is blocked needs it to be async, which would mean all calls to `isBlocked` will also need to be async and so on
// This is too much of a hassle at the moment as some UI code will have to be migrated to work with this async call.
await this . load ( ) ;
const toBlock = PubKey . cast ( user ) ;
if ( ! this . blockedNumbers . has ( toBlock . key ) ) {
this . blockedNumbers . add ( toBlock . key ) ;
await this . saveToDB ( BLOCKED_NUMBERS_ID , this . blockedNumbers ) ;
}
}
/ * *
* Unblock a user .
* This will only unblock the primary device of the user .
*
* @param user The user to unblock .
* /
public static async unblock ( user : string | PubKey ) : Promise < void > {
await this . load ( ) ;
const toUnblock = PubKey . cast ( user ) ;
if ( this . blockedNumbers . has ( toUnblock . key ) ) {
this . blockedNumbers . delete ( toUnblock . key ) ;
await this . saveToDB ( BLOCKED_NUMBERS_ID , this . blockedNumbers ) ;
}
}
/ * *
* Unblock all these users .
* This will only unblock the primary device of the user .
*
* @param user The user to unblock .
* /
public static async unblockAll ( users : Array < string > ) : Promise < void > {
await this . load ( ) ;
let changes = false ;
users . forEach ( user = > {
const toUnblock = PubKey . cast ( user ) ;
if ( this . blockedNumbers . has ( toUnblock . key ) ) {
this . blockedNumbers . delete ( toUnblock . key ) ;
changes = true ;
}
} ) ;
users . map ( user = > {
const found = getConversationController ( ) . get ( user ) ;
if ( found ) {
found . triggerUIRefresh ( ) ;
}
} ) ;
if ( changes ) {
await this . saveToDB ( BLOCKED_NUMBERS_ID , this . blockedNumbers ) ;
}
}
public static async setBlocked ( user : string | PubKey , blocked : boolean ) : Promise < void > {
if ( blocked ) {
return BlockedNumberController . block ( user ) ;
}
return BlockedNumberController . unblock ( user ) ;
}
public static async setGroupBlocked ( groupId : string | PubKey , blocked : boolean ) : Promise < void > {
if ( blocked ) {
return BlockedNumberController . blockGroup ( groupId ) ;
}
return BlockedNumberController . unblockGroup ( groupId ) ;
}
public static async blockGroup ( groupId : string | PubKey ) : Promise < void > {
await this . load ( ) ;
const id = PubKey . cast ( groupId ) ;
this . blockedGroups . add ( id . key ) ;
await this . saveToDB ( BLOCKED_GROUPS_ID , this . blockedGroups ) ;
}
public static async unblockGroup ( groupId : string | PubKey ) : Promise < void > {
await this . load ( ) ;
const id = PubKey . cast ( groupId ) ;
this . blockedGroups . delete ( id . key ) ;
await this . saveToDB ( BLOCKED_GROUPS_ID , this . blockedGroups ) ;
}
public static getBlockedNumbers ( ) : Array < string > {
return [ . . . this . blockedNumbers ] ;
}
public static getBlockedGroups ( ) : Array < string > {
return [ . . . this . blockedGroups ] ;
}
// ---- DB
public static async load() {
if ( ! this . loaded ) {
this . blockedNumbers = await this . getNumbersFromDB ( BLOCKED_NUMBERS_ID ) ;
this . blockedGroups = await this . getNumbersFromDB ( BLOCKED_GROUPS_ID ) ;
this . loaded = true ;
}
}
public static reset() {
this . loaded = false ;
this . blockedNumbers = new Set ( ) ;
this . blockedGroups = new Set ( ) ;
}
private static async getNumbersFromDB ( id : string ) : Promise < Set < string > > {
const data = await Data . getItemById ( id ) ;
if ( ! data || ! data . value ) {
return new Set ( ) ;
}
return new Set ( data . value ) ;
}
private static async saveToDB ( id : string , numbers : Set < string > ) : Promise < void > {
await Data . createOrUpdateItem ( {
id ,
value : [ . . . numbers ] ,
} ) ;
}
}