Privacy updates
This commit is contained in:
parent
64f2a64351
commit
b8f98e76c2
@ -122,9 +122,9 @@ export default class PrivacySection {
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
/* setTimeout(() => {
|
||||
this.setRadio(PrivacyType.Contacts);
|
||||
}, 0);
|
||||
}, 0); */
|
||||
|
||||
const promise = appPrivacyManager.getPrivacy(options.inputKey).then(rules => {
|
||||
const details = appPrivacyManager.getPrivacyRulesDetails(rules);
|
||||
|
@ -177,7 +177,12 @@ export default class Scrollable extends ScrollableBase {
|
||||
};
|
||||
|
||||
public checkForTriggers = () => {
|
||||
if((!this.onScrolledTop && !this.onScrolledBottom) || this.isHeavyAnimationInProgress) return;
|
||||
if((!this.onScrolledTop && !this.onScrolledBottom)) return;
|
||||
|
||||
if(this.isHeavyAnimationInProgress) {
|
||||
this.onScroll();
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollHeight = this.container.scrollHeight;
|
||||
if(!scrollHeight) { // незачем вызывать триггеры если блок пустой или не виден
|
||||
|
@ -10,8 +10,10 @@ import ButtonMenu from "../../buttonMenu";
|
||||
import PopupConfirmAction from "../../popups/confirmAction";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import { toast } from "../../toast";
|
||||
import AppPrivacyAndSecurityTab from "./privacyAndSecurity";
|
||||
|
||||
export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
public privacyTab: AppPrivacyAndSecurityTab;
|
||||
public authorizations: Authorization.authorization[];
|
||||
private menuElement: HTMLElement;
|
||||
|
||||
@ -57,11 +59,15 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
text: 'TERMINATE',
|
||||
isDanger: true,
|
||||
callback: () => {
|
||||
toggleDisability([btnTerminate], true);
|
||||
const b = [btnTerminate];
|
||||
toggleDisability(b, true);
|
||||
apiManager.invokeApi('auth.resetAuthorizations').then(value => {
|
||||
//toggleDisability([btnTerminate], false);
|
||||
btnTerminate.remove();
|
||||
otherSection.container.remove();
|
||||
this.privacyTab.updateActiveSessions();
|
||||
}, onError).finally(() => {
|
||||
toggleDisability(b, false);
|
||||
});
|
||||
}
|
||||
}], {
|
||||
@ -90,6 +96,12 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
|
||||
this.scrollable.append(otherSection.container);
|
||||
|
||||
const onError = (err: any) => {
|
||||
if(err.type === 'FRESH_RESET_AUTHORISATION_FORBIDDEN') {
|
||||
toast('For security reasons, you can\'t terminate older sessions from a device that you\'ve just connected. Please use an earlier connection or wait for a few hours.');
|
||||
}
|
||||
};
|
||||
|
||||
let target: HTMLElement;
|
||||
const onTerminateClick = () => {
|
||||
const hash = target.dataset.hash;
|
||||
@ -102,12 +114,9 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
.then(value => {
|
||||
if(value) {
|
||||
target.remove();
|
||||
this.privacyTab.updateActiveSessions();
|
||||
}
|
||||
}, (err) => {
|
||||
if(err.type === 'FRESH_RESET_AUTHORISATION_FORBIDDEN') {
|
||||
toast('For security reasons, you can\'t terminate older sessions from a device that you\'ve just connected. Please use an earlier connection or wait for a few hours.');
|
||||
}
|
||||
});
|
||||
}, onError);
|
||||
}
|
||||
}], {
|
||||
title: 'Terminate Session',
|
||||
|
@ -103,6 +103,33 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const LOAD_COUNT = 50;
|
||||
let loading = false;
|
||||
this.scrollable.onScrolledBottom = () => {
|
||||
if(loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
appUsersManager.getBlocked(list.childElementCount, LOAD_COUNT).then(res => {
|
||||
for(const peerId of res.peerIds) {
|
||||
add(peerId, true);
|
||||
}
|
||||
|
||||
if(res.peerIds.length < LOAD_COUNT) {
|
||||
this.scrollable.onScrolledBottom = null;
|
||||
}
|
||||
|
||||
this.scrollable.checkForTriggers();
|
||||
}).finally(() => {
|
||||
loading = false;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
onOpenAfterTimeout() {
|
||||
this.scrollable.onScroll();
|
||||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { SliderSuperTab } from "../../slider";
|
||||
import { generateSection, SettingSection } from "..";
|
||||
import Row from "../../row";
|
||||
import { AccountPassword, Authorization, InputPrivacyKey, PrivacyRule } from "../../../layer";
|
||||
import { AccountPassword, Authorization, InputPrivacyKey } from "../../../layer";
|
||||
import appPrivacyManager, { PrivacyType } from "../../../lib/appManagers/appPrivacyManager";
|
||||
import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber";
|
||||
import AppTwoStepVerificationTab from "./2fa";
|
||||
@ -17,14 +17,20 @@ import AppActiveSessionsTab from "./activeSessions";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import AppBlockedUsersTab from "./blockedUsers";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
private activeSessionsRow: Row;
|
||||
private authorizations: Authorization.authorization[];
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('privacy-container');
|
||||
this.title.innerText = 'Privacy and Security';
|
||||
|
||||
const section = generateSection.bind(null, this.scrollable);
|
||||
|
||||
const SUBTITLE = 'Loading...';
|
||||
|
||||
{
|
||||
const section = new SettingSection({noDelimiter: true});
|
||||
|
||||
@ -32,7 +38,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
const blockedUsersRow = new Row({
|
||||
icon: 'deleteuser',
|
||||
title: 'Blocked Users',
|
||||
subtitle: 'Loading...',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
const tab = new AppBlockedUsersTab(this.slider);
|
||||
tab.peerIds = blockedPeerIds;
|
||||
@ -45,7 +51,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
const twoFactorRowOptions = {
|
||||
icon: 'lock',
|
||||
title: 'Two-Step Verification',
|
||||
subtitle: 'Loading...',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: (e: Event) => {
|
||||
let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab | AppTwoStepVerificationEmailConfirmationTab;
|
||||
if(passwordState.pFlags.has_password) {
|
||||
@ -68,24 +74,39 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
const twoFactorRow = new Row(twoFactorRowOptions);
|
||||
twoFactorRow.freezed = true;
|
||||
|
||||
const activeSessionRow = new Row({
|
||||
const activeSessionsRow = this.activeSessionsRow = new Row({
|
||||
icon: 'activesessions',
|
||||
title: 'Active Sessions',
|
||||
subtitle: 'Loading...',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
const tab = new AppActiveSessionsTab(this.slider);
|
||||
tab.authorizations = authorizations;
|
||||
tab.privacyTab = this;
|
||||
tab.authorizations = this.authorizations;
|
||||
tab.open();
|
||||
}
|
||||
});
|
||||
activeSessionRow.freezed = true;
|
||||
activeSessionsRow.freezed = true;
|
||||
|
||||
section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionRow.container);
|
||||
section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionsRow.container);
|
||||
this.scrollable.append(section.container);
|
||||
|
||||
let blockedCount: number;
|
||||
const setBlockedCount = (count: number) => {
|
||||
blockedCount = count;
|
||||
blockedUsersRow.subtitle.innerText = count + ' ' + (count !== 1 ? 'users' : 'user');
|
||||
};
|
||||
|
||||
this.listenerSetter.add(rootScope, 'peer_block', (update) => {
|
||||
const {blocked, peerId} = update;
|
||||
if(!blocked) blockedPeerIds.findAndSplice(p => p === peerId);
|
||||
else blockedPeerIds.unshift(peerId);
|
||||
blockedCount += blocked ? 1 : -1;
|
||||
setBlockedCount(blockedCount);
|
||||
});
|
||||
|
||||
appUsersManager.getBlocked().then(res => {
|
||||
blockedUsersRow.freezed = false;
|
||||
blockedUsersRow.subtitle.innerText = res.count + ' ' + (res.count !== 1 ? 'users' : 'user');
|
||||
setBlockedCount(res.count);
|
||||
blockedPeerIds = res.peerIds;
|
||||
});
|
||||
|
||||
@ -97,13 +118,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
//console.log('password state', state);
|
||||
});
|
||||
|
||||
let authorizations: Authorization.authorization[];
|
||||
apiManager.invokeApi('account.getAuthorizations').then(auths => {
|
||||
activeSessionRow.freezed = false;
|
||||
authorizations = auths.authorizations;
|
||||
activeSessionRow.subtitle.innerText = authorizations.length + ' ' + (authorizations.length !== 1 ? 'devices' : 'device');
|
||||
console.log('auths', auths);
|
||||
});
|
||||
this.updateActiveSessions();
|
||||
}
|
||||
|
||||
{
|
||||
@ -117,7 +132,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
const numberVisibilityRow = rowsByKeys['inputPrivacyKeyPhoneNumber'] = new Row({
|
||||
title: 'Who can see my phone number?',
|
||||
subtitle: 'My Contacts',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
new AppPrivacyPhoneNumberTab(this.slider).open()
|
||||
}
|
||||
@ -125,7 +140,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({
|
||||
title: 'Who can see your Last Seen time?',
|
||||
subtitle: 'Everybody',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
new AppPrivacyLastSeenTab(this.slider).open()
|
||||
}
|
||||
@ -133,7 +148,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({
|
||||
title: 'Who can see my profile photo?',
|
||||
subtitle: 'Everybody',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
new AppPrivacyProfilePhotoTab(this.slider).open();
|
||||
}
|
||||
@ -141,7 +156,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({
|
||||
title: 'Who can call me?',
|
||||
subtitle: 'Everybody',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
new AppPrivacyCallsTab(this.slider).open();
|
||||
}
|
||||
@ -149,7 +164,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({
|
||||
title: 'Who can add a link to my account when forwarding my messages?',
|
||||
subtitle: 'Everybody',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
new AppPrivacyForwardMessagesTab(this.slider).open();
|
||||
}
|
||||
@ -157,15 +172,19 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
|
||||
const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({
|
||||
title: 'Who can add me to group chats?',
|
||||
subtitle: 'Everybody',
|
||||
subtitle: SUBTITLE,
|
||||
clickable: () => {
|
||||
new AppPrivacyAddToGroupsTab(this.slider).open();
|
||||
}
|
||||
});
|
||||
|
||||
for(const key in rowsByKeys) {
|
||||
const row = rowsByKeys[key as keyof typeof rowsByKeys];
|
||||
appPrivacyManager.getPrivacy(key as keyof typeof rowsByKeys).then(rules => {
|
||||
const updatePrivacyRow = (key: InputPrivacyKey['_']) => {
|
||||
const row = rowsByKeys[key];
|
||||
if(!row) {
|
||||
return;
|
||||
}
|
||||
|
||||
appPrivacyManager.getPrivacy(key).then(rules => {
|
||||
const details = appPrivacyManager.getPrivacyRulesDetails(rules);
|
||||
const type = details.type === PrivacyType.Everybody ? 'Everybody' : (details.type === PrivacyType.Contacts ? 'My Contacts' : 'Nobody');
|
||||
const disallowLength = details.disallowPeers.users.length + details.disallowPeers.chats.length;
|
||||
@ -173,9 +192,30 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
const str = type + (disallowLength || allowLength ? ` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})` : '');
|
||||
row.subtitle.innerHTML = str;
|
||||
});
|
||||
};
|
||||
|
||||
for(const key in rowsByKeys) {
|
||||
updatePrivacyRow(key as keyof typeof rowsByKeys);
|
||||
}
|
||||
|
||||
rootScope.on('privacy_update', (update) => {
|
||||
let key: string = update.key._;
|
||||
key = key[0].toUpperCase() + key.slice(1);
|
||||
key = 'input' + key;
|
||||
|
||||
updatePrivacyRow(key as any);
|
||||
});
|
||||
|
||||
container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, callRow.container, linkAccountRow.container, groupChatsAddRow.container);
|
||||
}
|
||||
}
|
||||
|
||||
public updateActiveSessions() {
|
||||
apiManager.invokeApi('account.getAuthorizations').then(auths => {
|
||||
this.activeSessionsRow.freezed = false;
|
||||
this.authorizations = auths.authorizations;
|
||||
this.activeSessionsRow.subtitle.innerText = this.authorizations.length + ' ' + (this.authorizations.length !== 1 ? 'devices' : 'device');
|
||||
//console.log('auths', auths);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
import { InputPrivacyKey, InputPrivacyRule, PrivacyRule } from "../../layer";
|
||||
import { InputPrivacyKey, InputPrivacyRule, PrivacyRule, Update, PrivacyKey } from "../../layer";
|
||||
import apiManager from "../mtproto/mtprotoworker";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import appUsersManager from "./appUsersManager";
|
||||
import apiUpdatesManager from "./apiUpdatesManager";
|
||||
import rootScope from "../rootScope";
|
||||
|
||||
export enum PrivacyType {
|
||||
Everybody = 2,
|
||||
@ -11,8 +13,27 @@ export enum PrivacyType {
|
||||
}
|
||||
|
||||
export class AppPrivacyManager {
|
||||
constructor() {
|
||||
private privacy: Partial<{
|
||||
[key in PrivacyKey['_']]: PrivacyRule[] | Promise<PrivacyRule[]>
|
||||
}> = {};
|
||||
|
||||
constructor() {
|
||||
rootScope.on('apiUpdate', (e) => {
|
||||
const update = e as Update;
|
||||
|
||||
switch(update._) {
|
||||
case 'updatePrivacy':
|
||||
const key = update.key._;
|
||||
this.privacy[key] = update.rules;
|
||||
rootScope.broadcast('privacy_update', update);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public convertInputKeyToKey(inputKey: string) {
|
||||
let str = inputKey.replace('input', '');
|
||||
return (str[0].toLowerCase() + str.slice(1)) as string;
|
||||
}
|
||||
|
||||
public setPrivacy(inputKey: InputPrivacyKey['_'], rules: InputPrivacyRule[]) {
|
||||
@ -22,17 +43,39 @@ export class AppPrivacyManager {
|
||||
},
|
||||
rules
|
||||
}).then(privacyRules => {
|
||||
/* appUsersManager.saveApiUsers(privacyRules.users);
|
||||
appUsersManager.saveApiUsers(privacyRules.users);
|
||||
appChatsManager.saveApiChats(privacyRules.chats);
|
||||
|
||||
console.log('privacy rules', inputKey, privacyRules, privacyRules.rules); */
|
||||
apiUpdatesManager.processUpdateMessage({
|
||||
_: 'updateShort',
|
||||
update: {
|
||||
_: 'updatePrivacy',
|
||||
key: {
|
||||
_: this.convertInputKeyToKey(inputKey)
|
||||
},
|
||||
rules: rules.map(inputRule => {
|
||||
const rule: PrivacyRule = {} as any;
|
||||
Object.assign(rule, inputRule);
|
||||
rule._ = this.convertInputKeyToKey(rule._) as any;
|
||||
return rule;
|
||||
})
|
||||
} as Update.updatePrivacy
|
||||
});
|
||||
|
||||
//console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);
|
||||
|
||||
return privacyRules.rules;
|
||||
});
|
||||
}
|
||||
|
||||
public getPrivacy(inputKey: InputPrivacyKey['_']) {
|
||||
return apiManager.invokeApi('account.getPrivacy', {
|
||||
const privacyKey: PrivacyKey['_'] = this.convertInputKeyToKey(inputKey) as any;
|
||||
const rules = this.privacy[privacyKey];
|
||||
if(rules) {
|
||||
return Promise.resolve(rules);
|
||||
}
|
||||
|
||||
return this.privacy[privacyKey] = apiManager.invokeApi('account.getPrivacy', {
|
||||
key: {
|
||||
_: inputKey
|
||||
}
|
||||
@ -42,7 +85,7 @@ export class AppPrivacyManager {
|
||||
|
||||
//console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);
|
||||
|
||||
return privacyRules.rules;
|
||||
return this.privacy[privacyKey] = privacyRules.rules;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export class AppUsersManager {
|
||||
private contactsFillPromise: Promise<Set<number>>;
|
||||
public contactsList: Set<number> = new Set();
|
||||
private updatedContactsList = false;
|
||||
|
||||
|
||||
private getTopPeersPromise: Promise<number[]>;
|
||||
|
||||
constructor() {
|
||||
|
@ -92,6 +92,8 @@ type BroadcastEvents = {
|
||||
'overlay_toggle': boolean,
|
||||
|
||||
'background_change': void,
|
||||
|
||||
'privacy_update': Update.updatePrivacy
|
||||
};
|
||||
|
||||
class RootScope extends EventListenerBase<any> {
|
||||
@ -126,11 +128,11 @@ class RootScope extends EventListenerBase<any> {
|
||||
}
|
||||
|
||||
public broadcast = <T extends keyof BroadcastEvents>(name: T, detail?: BroadcastEvents[T]) => {
|
||||
//if(DEBUG) {
|
||||
/* //if(DEBUG) {
|
||||
if(name !== 'user_update') {
|
||||
console.debug('Broadcasting ' + name + ' event, with args:', detail);
|
||||
}
|
||||
//}
|
||||
//} */
|
||||
|
||||
this.setListenerResult(name, detail);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user