Browse Source

Privacy updates

master
morethanwords 3 years ago
parent
commit
b8f98e76c2
  1. 4
      src/components/privacySection.ts
  2. 7
      src/components/scrollable.ts
  3. 21
      src/components/sidebarLeft/tabs/activeSessions.ts
  4. 27
      src/components/sidebarLeft/tabs/blockedUsers.ts
  5. 90
      src/components/sidebarLeft/tabs/privacyAndSecurity.ts
  6. 53
      src/lib/appManagers/appPrivacyManager.ts
  7. 2
      src/lib/appManagers/appUsersManager.ts
  8. 6
      src/lib/rootScope.ts

4
src/components/privacySection.ts

@ -122,9 +122,9 @@ export default class PrivacySection { @@ -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);

7
src/components/scrollable.ts

@ -177,7 +177,12 @@ export default class Scrollable extends ScrollableBase { @@ -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) { // незачем вызывать триггеры если блок пустой или не виден

21
src/components/sidebarLeft/tabs/activeSessions.ts

@ -10,8 +10,10 @@ import ButtonMenu from "../../buttonMenu"; @@ -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 { @@ -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 { @@ -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 { @@ -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',

27
src/components/sidebarLeft/tabs/blockedUsers.ts

@ -103,6 +103,33 @@ export default class AppBlockedUsersTab extends SliderSuperTab { @@ -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() {

90
src/components/sidebarLeft/tabs/privacyAndSecurity.ts

@ -1,7 +1,7 @@ @@ -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"; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);
});
}
}

53
src/lib/appManagers/appPrivacyManager.ts

@ -1,8 +1,10 @@ @@ -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 { @@ -11,8 +13,27 @@ export enum PrivacyType {
}
export class AppPrivacyManager {
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 { @@ -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 { @@ -42,7 +85,7 @@ export class AppPrivacyManager {
//console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);
return privacyRules.rules;
return this.privacy[privacyKey] = privacyRules.rules;
});
}

2
src/lib/appManagers/appUsersManager.ts

@ -28,7 +28,7 @@ export class AppUsersManager { @@ -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() {

6
src/lib/rootScope.ts

@ -92,6 +92,8 @@ type BroadcastEvents = { @@ -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> { @@ -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…
Cancel
Save