commit
f11e0f2cd0
@ -1,68 +0,0 @@
|
||||
/* global , Whisper, storage */
|
||||
/* global textsecure: false */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
const blockedNumbers = new Whisper.BlockedNumberCollection();
|
||||
window.getBlockedNumbers = () => blockedNumbers;
|
||||
|
||||
window.BlockedNumberController = {
|
||||
reset() {
|
||||
this.unblockAll();
|
||||
blockedNumbers.reset([]);
|
||||
},
|
||||
refresh() {
|
||||
window.log.info('BlockedNumberController: starting initial fetch');
|
||||
|
||||
if (!storage) {
|
||||
throw new Error(
|
||||
'BlockedNumberController: Could not load blocked numbers'
|
||||
);
|
||||
}
|
||||
|
||||
// Add the numbers to the collection
|
||||
const numbers = storage.getBlockedNumbers();
|
||||
blockedNumbers.reset(numbers.map(number => ({ number })));
|
||||
},
|
||||
block(number) {
|
||||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
|
||||
// Make sure we don't block ourselves
|
||||
if (ourNumber === number) {
|
||||
window.log.info('BlockedNumberController: Cannot block yourself!');
|
||||
return;
|
||||
}
|
||||
|
||||
storage.addBlockedNumber(number);
|
||||
|
||||
// Make sure we don't add duplicates
|
||||
if (blockedNumbers.getModel(number)) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockedNumbers.add({ number });
|
||||
},
|
||||
unblock(number) {
|
||||
storage.removeBlockedNumber(number);
|
||||
|
||||
// Remove the model from our collection
|
||||
const model = blockedNumbers.getModel(number);
|
||||
if (model) {
|
||||
blockedNumbers.remove(model);
|
||||
}
|
||||
},
|
||||
unblockAll() {
|
||||
const numbers = blockedNumbers.map(m => m.get('number'));
|
||||
numbers.forEach(n => this.unblock(n));
|
||||
},
|
||||
isBlocked(number) {
|
||||
return storage.isBlocked(number);
|
||||
},
|
||||
};
|
||||
})();
|
@ -1,102 +0,0 @@
|
||||
/* global BlockedNumberController: false */
|
||||
/* global getBlockedNumbers: false */
|
||||
/* global Whisper: false */
|
||||
/* global storage: false */
|
||||
/* global i18n: false */
|
||||
|
||||
/* eslint-disable no-new */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.BlockedNumberView = Whisper.View.extend({
|
||||
templateName: 'blockedUserSettings',
|
||||
className: 'blockedUserSettings',
|
||||
events: {
|
||||
'click .unblock-button': 'onUnblock',
|
||||
},
|
||||
initialize() {
|
||||
storage.onready(() => {
|
||||
BlockedNumberController.refresh();
|
||||
this.collection = getBlockedNumbers();
|
||||
this.listView = new Whisper.BlockedNumberListView({
|
||||
collection: this.collection,
|
||||
});
|
||||
|
||||
this.listView.render();
|
||||
this.blockedUserSettings = this.$('.blocked-user-settings');
|
||||
this.blockedUserSettings.prepend(this.listView.el);
|
||||
});
|
||||
},
|
||||
render_attributes() {
|
||||
return {
|
||||
blockedHeader: i18n('settingsUnblockHeader'),
|
||||
unblockMessage: i18n('unblockUser'),
|
||||
};
|
||||
},
|
||||
onUnblock() {
|
||||
const number = this.$('select option:selected').val();
|
||||
if (!number) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BlockedNumberController.isBlocked(number)) {
|
||||
BlockedNumberController.unblock(number);
|
||||
window.onUnblockNumber(number);
|
||||
this.listView.collection.remove(
|
||||
this.listView.collection.where({ number })
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Whisper.BlockedNumberListView = Whisper.View.extend({
|
||||
tagName: 'select',
|
||||
initialize(options) {
|
||||
this.options = options || {};
|
||||
this.listenTo(this.collection, 'add', this.addOne);
|
||||
this.listenTo(this.collection, 'reset', this.addAll);
|
||||
this.listenTo(this.collection, 'remove', this.addAll);
|
||||
},
|
||||
addOne(model) {
|
||||
const number = model.get('number');
|
||||
if (number) {
|
||||
this.$el.append(
|
||||
`<option value="${number}">${this.truncate(number, 25)}</option>`
|
||||
);
|
||||
}
|
||||
},
|
||||
addAll() {
|
||||
this.$el.html('');
|
||||
this.collection.each(this.addOne, this);
|
||||
},
|
||||
truncate(string, limit) {
|
||||
// Make sure an element and number of items to truncate is provided
|
||||
if (!string || !limit) {
|
||||
return string;
|
||||
}
|
||||
|
||||
// Get the inner content of the element
|
||||
let content = string.trim();
|
||||
|
||||
// Convert the content into an array of words
|
||||
// Remove any words above the limit
|
||||
content = content.slice(0, limit);
|
||||
|
||||
// Convert the array of words back into a string
|
||||
// If there's content to add after it, add it
|
||||
if (string.length > limit) {
|
||||
content = `${content}...`;
|
||||
}
|
||||
|
||||
return content;
|
||||
},
|
||||
render() {
|
||||
this.addAll();
|
||||
return this;
|
||||
},
|
||||
});
|
||||
})();
|
@ -1,163 +0,0 @@
|
||||
/* global textsecure, BlockedNumberController, storage */
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('Blocked Number Controller', () => {
|
||||
beforeEach(async () => {
|
||||
// Purge everything manually
|
||||
const numbers = storage.getBlockedNumbers();
|
||||
numbers.forEach(storage.removeBlockedNumber);
|
||||
window.getBlockedNumbers().reset([]);
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('clears blocked numbers', () => {
|
||||
BlockedNumberController.block('1');
|
||||
assert.isNotEmpty(storage.getBlockedNumbers());
|
||||
assert.isNotEmpty(window.getBlockedNumbers().models);
|
||||
|
||||
BlockedNumberController.reset();
|
||||
assert.isEmpty(storage.getBlockedNumbers());
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh', () => {
|
||||
it('loads blocked numbers from storage', () => {
|
||||
BlockedNumberController.refresh();
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
|
||||
storage.addBlockedNumber('1');
|
||||
storage.addBlockedNumber('2');
|
||||
BlockedNumberController.refresh();
|
||||
|
||||
const blocked = window.getBlockedNumbers().map(m => m.get('number'));
|
||||
assert.lengthOf(blocked, 2);
|
||||
assert.deepEqual(['1', '2'], blocked.sort());
|
||||
});
|
||||
|
||||
it('overrides old numbers if we refresh again', () => {
|
||||
BlockedNumberController.refresh();
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
|
||||
storage.addBlockedNumber('1');
|
||||
BlockedNumberController.refresh();
|
||||
assert.isNotEmpty(
|
||||
window.getBlockedNumbers().find(m => m.get('number') === '1')
|
||||
);
|
||||
|
||||
storage.removeBlockedNumber('1');
|
||||
storage.addBlockedNumber('2');
|
||||
BlockedNumberController.refresh();
|
||||
assert.isNotEmpty(
|
||||
window.getBlockedNumbers().find(m => m.get('number') === '2')
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if storage is invalid', () => {
|
||||
const _storage = window.storage;
|
||||
window.storage = null;
|
||||
assert.throws(
|
||||
() => BlockedNumberController.refresh(),
|
||||
'BlockedNumberController: Could not load blocked numbers'
|
||||
);
|
||||
window.storage = _storage;
|
||||
});
|
||||
});
|
||||
|
||||
describe('block', () => {
|
||||
beforeEach(() => {
|
||||
BlockedNumberController.refresh();
|
||||
assert.isEmpty(storage.getBlockedNumbers());
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
});
|
||||
|
||||
it('adds number to the blocked list', () => {
|
||||
BlockedNumberController.block('1');
|
||||
|
||||
const numbers = window.getBlockedNumbers().models;
|
||||
assert.lengthOf(numbers, 1);
|
||||
assert.strictEqual('1', numbers[0].get('number'));
|
||||
assert.deepEqual(['1'], storage.getBlockedNumbers());
|
||||
});
|
||||
|
||||
it('only blocks the same number once', () => {
|
||||
BlockedNumberController.block('2');
|
||||
BlockedNumberController.block('2');
|
||||
assert.lengthOf(window.getBlockedNumbers().models, 1);
|
||||
assert.deepEqual(['2'], storage.getBlockedNumbers());
|
||||
});
|
||||
|
||||
it('does not block our own number', () => {
|
||||
BlockedNumberController.block(textsecure.storage.user.getNumber());
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
assert.isEmpty(storage.getBlockedNumbers());
|
||||
});
|
||||
});
|
||||
|
||||
describe('unblock', () => {
|
||||
beforeEach(() => {
|
||||
BlockedNumberController.refresh();
|
||||
assert.isEmpty(storage.getBlockedNumbers());
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
});
|
||||
|
||||
it('removes number from the blocked list', () => {
|
||||
BlockedNumberController.block('1');
|
||||
BlockedNumberController.block('2');
|
||||
|
||||
assert.lengthOf(window.getBlockedNumbers().models, 2);
|
||||
assert.lengthOf(storage.getBlockedNumbers(), 2);
|
||||
|
||||
BlockedNumberController.unblock('1');
|
||||
|
||||
const numbers = window.getBlockedNumbers().models;
|
||||
assert.lengthOf(numbers, 1);
|
||||
assert.isEmpty(numbers.filter(n => n.get('number') === '1'));
|
||||
assert.deepEqual(['2'], storage.getBlockedNumbers());
|
||||
});
|
||||
|
||||
it('removes number from the blocked list even if it is not present in the collection', () => {
|
||||
BlockedNumberController.block('1');
|
||||
BlockedNumberController.block('2');
|
||||
window.getBlockedNumbers().reset([]);
|
||||
|
||||
assert.isEmpty(window.getBlockedNumbers().models);
|
||||
assert.lengthOf(storage.getBlockedNumbers(), 2);
|
||||
|
||||
BlockedNumberController.unblock('1');
|
||||
assert.deepEqual(['2'], storage.getBlockedNumbers());
|
||||
});
|
||||
});
|
||||
|
||||
describe('unblockAll', () => {
|
||||
it('removes all our blocked numbers', () => {
|
||||
BlockedNumberController.refresh();
|
||||
|
||||
BlockedNumberController.block('1');
|
||||
BlockedNumberController.block('2');
|
||||
BlockedNumberController.block('3');
|
||||
|
||||
assert.lengthOf(window.getBlockedNumbers().models, 3);
|
||||
assert.lengthOf(storage.getBlockedNumbers(), 3);
|
||||
|
||||
BlockedNumberController.unblockAll();
|
||||
|
||||
assert.lengthOf(window.getBlockedNumbers().models, 0);
|
||||
assert.lengthOf(storage.getBlockedNumbers(), 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBlocked', () => {
|
||||
it('returns whether a number is blocked', () => {
|
||||
BlockedNumberController.refresh();
|
||||
|
||||
BlockedNumberController.block('1');
|
||||
assert.isOk(BlockedNumberController.isBlocked('1'));
|
||||
assert.isNotOk(BlockedNumberController.isBlocked('2'));
|
||||
|
||||
BlockedNumberController.unblock('1');
|
||||
assert.isNotOk(BlockedNumberController.isBlocked('1'));
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,240 @@
|
||||
import { expect } from 'chai';
|
||||
import * as crypto from 'crypto';
|
||||
import Sinon, * as sinon from 'sinon';
|
||||
import { BlockedNumberController } from '../../util/blockedNumberController';
|
||||
import { TestUtils } from '../test-utils';
|
||||
import { PubKey } from '../../session/types';
|
||||
import { MultiDeviceProtocol } from '../../session/protocols';
|
||||
import { UserUtil } from '../../util';
|
||||
|
||||
describe('BlockedNumberController', () => {
|
||||
const sandbox = sinon.createSandbox();
|
||||
let memoryDB: { [key: string]: any };
|
||||
beforeEach(() => {
|
||||
memoryDB = {};
|
||||
|
||||
TestUtils.stubData('createOrUpdateItem').callsFake(data => {
|
||||
memoryDB[data.id] = data.value;
|
||||
});
|
||||
|
||||
TestUtils.stubData('getItemById').callsFake(id => {
|
||||
if (!memoryDB[id]) {
|
||||
return undefined;
|
||||
}
|
||||
const value = memoryDB[id];
|
||||
return {
|
||||
id,
|
||||
value,
|
||||
};
|
||||
});
|
||||
|
||||
BlockedNumberController.reset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
TestUtils.restoreStubs();
|
||||
});
|
||||
|
||||
describe('load', async () => {
|
||||
it('should load data from the database', async () => {
|
||||
const normal = TestUtils.generateFakePubKey();
|
||||
const group = TestUtils.generateFakePubKey();
|
||||
memoryDB.blocked = [normal.key];
|
||||
memoryDB['blocked-groups'] = [group.key];
|
||||
await BlockedNumberController.load();
|
||||
|
||||
const blockedNumbers = BlockedNumberController.getBlockedNumbers();
|
||||
const blockedGroups = BlockedNumberController.getBlockedGroups();
|
||||
|
||||
expect(blockedNumbers).to.have.lengthOf(1);
|
||||
expect(blockedNumbers).to.include(normal.key);
|
||||
expect(blockedGroups).to.have.lengthOf(1);
|
||||
expect(blockedGroups).to.include(group.key);
|
||||
});
|
||||
|
||||
it('should return empty if nothing in the db exists', async () => {
|
||||
await BlockedNumberController.load();
|
||||
const blockedNumbers = BlockedNumberController.getBlockedNumbers();
|
||||
const blockedGroups = BlockedNumberController.getBlockedGroups();
|
||||
|
||||
expect(blockedNumbers).to.be.empty;
|
||||
expect(blockedGroups).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
describe('block', async () => {
|
||||
it('should block the primary device of the user', async () => {
|
||||
const primary = TestUtils.generateFakePubKey();
|
||||
const secondary = TestUtils.generateFakePubKey();
|
||||
sandbox.stub(MultiDeviceProtocol, 'getPrimaryDevice').resolves(primary);
|
||||
|
||||
await BlockedNumberController.block(secondary);
|
||||
|
||||
const blockedNumbers = BlockedNumberController.getBlockedNumbers();
|
||||
expect(blockedNumbers).to.have.lengthOf(1);
|
||||
expect(blockedNumbers).to.include(primary.key);
|
||||
expect(memoryDB.blocked).to.include(primary.key);
|
||||
expect(BlockedNumberController.getBlockedGroups()).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
describe('unblock', async () => {
|
||||
it('should unblock the primary device', async () => {
|
||||
const primary = TestUtils.generateFakePubKey();
|
||||
const secondary = TestUtils.generateFakePubKey();
|
||||
memoryDB.blocked = [primary.key];
|
||||
sandbox.stub(MultiDeviceProtocol, 'getPrimaryDevice').resolves(primary);
|
||||
|
||||
await BlockedNumberController.unblock(secondary);
|
||||
|
||||
const blockedNumbers = BlockedNumberController.getBlockedNumbers();
|
||||
expect(blockedNumbers).to.be.empty;
|
||||
expect(memoryDB.blocked).to.be.empty;
|
||||
});
|
||||
|
||||
it('should only unblock if a device was blocked', async () => {
|
||||
const pubKey = TestUtils.generateFakePubKey();
|
||||
const another = TestUtils.generateFakePubKey();
|
||||
memoryDB.blocked = [pubKey.key, another.key];
|
||||
sandbox.stub(MultiDeviceProtocol, 'getPrimaryDevice').resolves(pubKey);
|
||||
|
||||
await BlockedNumberController.unblock(pubKey);
|
||||
|
||||
const blockedNumbers = BlockedNumberController.getBlockedNumbers();
|
||||
expect(blockedNumbers).to.have.lengthOf(1);
|
||||
expect(blockedNumbers).to.include(another.key);
|
||||
expect(memoryDB.blocked).to.have.lengthOf(1);
|
||||
expect(memoryDB.blocked).to.include(another.key);
|
||||
});
|
||||
});
|
||||
|
||||
describe('blockGroup', async () => {
|
||||
it('should block a group', async () => {
|
||||
const group = TestUtils.generateFakePubKey();
|
||||
|
||||
await BlockedNumberController.blockGroup(group);
|
||||
|
||||
const blockedGroups = BlockedNumberController.getBlockedGroups();
|
||||
expect(blockedGroups).to.have.lengthOf(1);
|
||||
expect(blockedGroups).to.include(group.key);
|
||||
expect(memoryDB['blocked-groups']).to.have.lengthOf(1);
|
||||
expect(memoryDB['blocked-groups']).to.include(group.key);
|
||||
expect(BlockedNumberController.getBlockedNumbers()).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
describe('unblockGroup', async () => {
|
||||
it('should unblock a group', async () => {
|
||||
const group = TestUtils.generateFakePubKey();
|
||||
const another = TestUtils.generateFakePubKey();
|
||||
memoryDB['blocked-groups'] = [group.key, another.key];
|
||||
|
||||
await BlockedNumberController.unblockGroup(group);
|
||||
|
||||
const blockedGroups = BlockedNumberController.getBlockedGroups();
|
||||
expect(blockedGroups).to.have.lengthOf(1);
|
||||
expect(blockedGroups).to.include(another.key);
|
||||
expect(memoryDB['blocked-groups']).to.have.lengthOf(1);
|
||||
expect(memoryDB['blocked-groups']).to.include(another.key);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBlocked', async () => {
|
||||
it('should return true if number is blocked', async () => {
|
||||
const pubKey = TestUtils.generateFakePubKey();
|
||||
const groupPubKey = TestUtils.generateFakePubKey();
|
||||
memoryDB.blocked = [pubKey.key];
|
||||
memoryDB['blocked-groups'] = [groupPubKey.key];
|
||||
await BlockedNumberController.load();
|
||||
expect(BlockedNumberController.isBlocked(pubKey.key)).to.equal(
|
||||
true,
|
||||
'Expected isBlocked to return true for user pubkey'
|
||||
);
|
||||
expect(BlockedNumberController.isBlocked(groupPubKey.key)).to.equal(
|
||||
false,
|
||||
'Expected isBlocked to return false for a group pubkey'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if number is not blocked', async () => {
|
||||
const pubKey = TestUtils.generateFakePubKey();
|
||||
memoryDB.blocked = [];
|
||||
await BlockedNumberController.load();
|
||||
expect(BlockedNumberController.isBlocked(pubKey.key)).to.equal(
|
||||
false,
|
||||
'Expected isBlocked to return false'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBlockedAsync', () => {
|
||||
let ourDevices: Array<PubKey>;
|
||||
beforeEach(() => {
|
||||
ourDevices = TestUtils.generateFakePubKeys(2);
|
||||
sandbox.stub(MultiDeviceProtocol, 'getOurDevices').resolves(ourDevices);
|
||||
});
|
||||
it('should return false for our device', async () => {
|
||||
for (const device of ourDevices) {
|
||||
const isBlocked = await BlockedNumberController.isBlockedAsync(device);
|
||||
expect(isBlocked).to.equal(
|
||||
false,
|
||||
'Expected our devices to return false'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return true if the primary device is blocked', async () => {
|
||||
const primary = TestUtils.generateFakePubKey();
|
||||
const secondary = TestUtils.generateFakePubKey();
|
||||
sandbox.stub(MultiDeviceProtocol, 'getPrimaryDevice').resolves(primary);
|
||||
memoryDB.blocked = [primary.key];
|
||||
|
||||
const isBlocked = await BlockedNumberController.isBlockedAsync(secondary);
|
||||
expect(isBlocked).to.equal(
|
||||
true,
|
||||
'Expected isBlockedAsync to return true.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if device is not blocked', async () => {
|
||||
const primary = TestUtils.generateFakePubKey();
|
||||
sandbox.stub(MultiDeviceProtocol, 'getPrimaryDevice').resolves(primary);
|
||||
memoryDB.blocked = [];
|
||||
|
||||
const isBlocked = await BlockedNumberController.isBlockedAsync(primary);
|
||||
expect(isBlocked).to.equal(
|
||||
false,
|
||||
'Expected isBlockedAsync to return false.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isGroupBlocked', async () => {
|
||||
it('should return true if group is blocked', async () => {
|
||||
const pubKey = TestUtils.generateFakePubKey();
|
||||
const groupPubKey = TestUtils.generateFakePubKey();
|
||||
memoryDB.blocked = [pubKey.key];
|
||||
memoryDB['blocked-groups'] = [groupPubKey.key];
|
||||
await BlockedNumberController.load();
|
||||
expect(BlockedNumberController.isGroupBlocked(pubKey.key)).to.equal(
|
||||
false,
|
||||
'Expected isGroupBlocked to return false for user pubkey'
|
||||
);
|
||||
expect(BlockedNumberController.isGroupBlocked(groupPubKey.key)).to.equal(
|
||||
true,
|
||||
'Expected isGroupBlocked to return true for a group pubkey'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if group is not blocked', async () => {
|
||||
const groupPubKey = TestUtils.generateFakePubKey();
|
||||
memoryDB['blocked-groups'] = [];
|
||||
await BlockedNumberController.load();
|
||||
expect(BlockedNumberController.isGroupBlocked(groupPubKey.key)).to.equal(
|
||||
false,
|
||||
'Expected isGroupBlocked to return false'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,148 @@
|
||||
import { createOrUpdateItem, getItemById } from '../../js/modules/data';
|
||||
import { PubKey } from '../session/types';
|
||||
import { MultiDeviceProtocol } from '../session/protocols';
|
||||
|
||||
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.
|
||||
* This will use `MultiDeviceProtocol` to determine wether a user is blocked or not.
|
||||
*
|
||||
* @param user The user.
|
||||
*/
|
||||
public static async isBlockedAsync(user: string | PubKey): Promise<boolean> {
|
||||
await this.load();
|
||||
const isOurDevice = await MultiDeviceProtocol.isOurDevice(user);
|
||||
if (isOurDevice) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const primary = await MultiDeviceProtocol.getPrimaryDevice(user);
|
||||
return this.blockedNumbers.has(primary.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 primary = await MultiDeviceProtocol.getPrimaryDevice(user);
|
||||
if (!this.blockedNumbers.has(primary.key)) {
|
||||
this.blockedNumbers.add(primary.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 primary = await MultiDeviceProtocol.getPrimaryDevice(user);
|
||||
if (this.blockedNumbers.has(primary.key)) {
|
||||
this.blockedNumbers.delete(primary.key);
|
||||
await this.saveToDB(BLOCKED_NUMBERS_ID, this.blockedNumbers);
|
||||
}
|
||||
}
|
||||
|
||||
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 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 createOrUpdateItem({
|
||||
id,
|
||||
value: [...numbers],
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue