Active sessions functions
This commit is contained in:
parent
0330059dd0
commit
ac313c94bd
@ -292,6 +292,7 @@ export default class ChatContextMenu {
|
||||
|
||||
this.element = ButtonMenu(this.buttons, this.chat.bubbles.listenerSetter);
|
||||
this.element.id = 'bubble-contextmenu';
|
||||
this.element.classList.add('contextmenu');
|
||||
this.chat.container.append(this.element);
|
||||
};
|
||||
|
||||
|
@ -83,6 +83,7 @@ export default class DialogsContextMenu {
|
||||
|
||||
this.element = ButtonMenu(this.buttons);
|
||||
this.element.id = 'dialogs-contextmenu';
|
||||
this.element.classList.add('contextmenu');
|
||||
document.getElementById('page-chats').append(this.element);
|
||||
}
|
||||
|
||||
|
@ -50,17 +50,17 @@ export default class PopupElement {
|
||||
this.header.prepend(this.btnClose);
|
||||
|
||||
this.btnClose.addEventListener('click', this.hide, {once: true});
|
||||
}
|
||||
|
||||
if(options.overlayClosable) {
|
||||
const onOverlayClick = (e: MouseEvent) => {
|
||||
if(!findUpClassName(e.target, 'popup-container')) {
|
||||
this.btnClose.click();
|
||||
this.element.removeEventListener('click', onOverlayClick);
|
||||
}
|
||||
};
|
||||
|
||||
this.element.addEventListener('click', onOverlayClick);
|
||||
}
|
||||
if(options.overlayClosable) {
|
||||
const onOverlayClick = (e: MouseEvent) => {
|
||||
if(!findUpClassName(e.target, 'popup-container')) {
|
||||
this.hide();
|
||||
this.element.removeEventListener('click', onOverlayClick);
|
||||
}
|
||||
};
|
||||
|
||||
this.element.addEventListener('click', onOverlayClick);
|
||||
}
|
||||
|
||||
if(options.withConfirm) {
|
||||
|
@ -2,75 +2,158 @@ import { SliderSuperTab } from "../../slider";
|
||||
import { SettingSection } from "..";
|
||||
import Button from "../../button";
|
||||
import Row from "../../row";
|
||||
import { Authorization } from "../../../layer";
|
||||
import { formatDateAccordingToToday } from "../../../helpers/date";
|
||||
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../../misc";
|
||||
import { attachClickEvent, findUpClassName, toggleDisability } from "../../../helpers/dom";
|
||||
import ButtonMenu from "../../buttonMenu";
|
||||
import PopupConfirmAction from "../../popups/confirmAction";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import { toast } from "../../toast";
|
||||
|
||||
export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
public authorizations: Authorization.authorization[];
|
||||
private menuElement: HTMLElement;
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('active-sessions-container');
|
||||
this.title.innerText = 'Active Sessions';
|
||||
|
||||
const Session = (options: {
|
||||
application: string,
|
||||
device: string,
|
||||
ip: string,
|
||||
location: string,
|
||||
time?: string
|
||||
}) => {
|
||||
const Session = (auth: Authorization.authorization) => {
|
||||
const row = new Row({
|
||||
title: options.application,
|
||||
subtitle: options.ip + ' - ' + options.location,
|
||||
title: [auth.app_name, auth.app_version].join(' '),
|
||||
subtitle: [auth.ip, auth.country].join(' - '),
|
||||
clickable: true,
|
||||
titleRight: options.time
|
||||
titleRight: auth.pFlags.current ? undefined : formatDateAccordingToToday(new Date(Math.max(auth.date_active, auth.date_created) * 1000))
|
||||
});
|
||||
|
||||
row.container.dataset.hash = auth.hash;
|
||||
|
||||
const midtitle = document.createElement('div');
|
||||
midtitle.classList.add('row-midtitle');
|
||||
midtitle.innerHTML = options.device;
|
||||
midtitle.innerHTML = [auth.device_model, auth.system_version].join(', ');
|
||||
|
||||
row.subtitle.parentElement.insertBefore(midtitle, row.subtitle);
|
||||
|
||||
return row;
|
||||
};
|
||||
|
||||
const authorizations = this.authorizations.slice();
|
||||
|
||||
{
|
||||
const section = new SettingSection({
|
||||
name: 'Current Session'
|
||||
});
|
||||
|
||||
const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'Terminate all other sessions'});
|
||||
const auth = authorizations.findAndSplice(auth => auth.pFlags.current);
|
||||
const session = Session(auth);
|
||||
|
||||
const session = Session({
|
||||
application: 'Telegram Web 1.0',
|
||||
device: 'Safari, macOS',
|
||||
ip: '216.3.128.12',
|
||||
location: 'Paris, France'
|
||||
});
|
||||
section.content.append(session.container);
|
||||
|
||||
section.content.append(session.container, btnTerminate);
|
||||
this.scrollable.append(section.container);
|
||||
}
|
||||
|
||||
{
|
||||
const section = new SettingSection({
|
||||
name: 'Other Sessions'
|
||||
});
|
||||
|
||||
[Session({
|
||||
application: 'Telegram iOS 5.12',
|
||||
device: 'iPhone X, iOS 13.2',
|
||||
ip: '216.3.128.12',
|
||||
location: 'Paris, France',
|
||||
time: '19:25'
|
||||
}), Session({
|
||||
application: 'Telegram Android 5.11',
|
||||
device: 'Samsung Galaxy S9, Android 9P',
|
||||
ip: '216.3.128.12',
|
||||
location: 'Paris, France',
|
||||
time: '16:34'
|
||||
})].forEach(session => {
|
||||
section.content.append(session.container);
|
||||
});
|
||||
if(authorizations.length) {
|
||||
const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'Terminate all other sessions'});
|
||||
attachClickEvent(btnTerminate, (e) => {
|
||||
new PopupConfirmAction('revoke-session', [{
|
||||
text: 'TERMINATE',
|
||||
isDanger: true,
|
||||
callback: () => {
|
||||
toggleDisability([btnTerminate], true);
|
||||
apiManager.invokeApi('auth.resetAuthorizations').then(value => {
|
||||
//toggleDisability([btnTerminate], false);
|
||||
btnTerminate.remove();
|
||||
otherSection.container.remove();
|
||||
});
|
||||
}
|
||||
}], {
|
||||
title: 'Terminate All Other Sessions',
|
||||
text: 'Are you sure you want to terminate all other sessions?'
|
||||
}).show();
|
||||
});
|
||||
|
||||
section.content.append(btnTerminate);
|
||||
}
|
||||
|
||||
this.scrollable.append(section.container);
|
||||
}
|
||||
|
||||
if(!authorizations.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const otherSection = new SettingSection({
|
||||
name: 'Other Sessions'
|
||||
});
|
||||
|
||||
authorizations.forEach(auth => {
|
||||
otherSection.content.append(Session(auth).container);
|
||||
});
|
||||
|
||||
this.scrollable.append(otherSection.container);
|
||||
|
||||
let target: HTMLElement;
|
||||
const onTerminateClick = () => {
|
||||
const hash = target.dataset.hash;
|
||||
|
||||
new PopupConfirmAction('revoke-session', [{
|
||||
text: 'TERMINATE',
|
||||
isDanger: true,
|
||||
callback: () => {
|
||||
apiManager.invokeApi('account.resetAuthorization', {hash})
|
||||
.then(value => {
|
||||
if(value) {
|
||||
target.remove();
|
||||
}
|
||||
}, (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.');
|
||||
}
|
||||
});
|
||||
}
|
||||
}], {
|
||||
title: 'Terminate Session',
|
||||
text: 'Do you want to terminate this session?'
|
||||
}).show();
|
||||
};
|
||||
|
||||
const element = this.menuElement = ButtonMenu([{
|
||||
icon: 'stop',
|
||||
text: 'Terminate',
|
||||
onClick: onTerminateClick
|
||||
}]);
|
||||
element.id = 'active-sessions-contextmenu';
|
||||
element.classList.add('contextmenu');
|
||||
|
||||
document.getElementById('page-chats').append(element);
|
||||
|
||||
attachContextMenuListener(this.scrollable.container, (e) => {
|
||||
target = findUpClassName(e.target, 'row');
|
||||
if(!target || target.dataset.hash === '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
if(e instanceof MouseEvent) e.preventDefault();
|
||||
// smth
|
||||
if(e instanceof MouseEvent) e.cancelBubble = true;
|
||||
|
||||
positionMenu(e, element);
|
||||
openBtnMenu(element);
|
||||
});
|
||||
|
||||
attachClickEvent(this.scrollable.container, (e) => {
|
||||
target = findUpClassName(e.target, 'row');
|
||||
if(!target || target.dataset.hash === '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
onTerminateClick();
|
||||
});
|
||||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
if(this.menuElement) {
|
||||
this.menuElement.remove();
|
||||
}
|
||||
|
||||
return super.onCloseAfterTimeout();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { SliderSuperTab } from "../../slider";
|
||||
import { generateSection, SettingSection } from "..";
|
||||
import Row from "../../row";
|
||||
import { AccountPassword, InputPrivacyKey, PrivacyRule } from "../../../layer";
|
||||
import { AccountPassword, Authorization, InputPrivacyKey, PrivacyRule } from "../../../layer";
|
||||
import appPrivacyManager, { PrivacyType } from "../../../lib/appManagers/appPrivacyManager";
|
||||
import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber";
|
||||
import AppTwoStepVerificationTab from "./2fa";
|
||||
@ -14,6 +14,7 @@ import AppPrivacyForwardMessagesTab from "./privacy/forwardMessages";
|
||||
import AppPrivacyAddToGroupsTab from "./privacy/addToGroups";
|
||||
import AppPrivacyCallsTab from "./privacy/calls";
|
||||
import AppActiveSessionsTab from "./activeSessions";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
protected init() {
|
||||
@ -62,11 +63,14 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
const activeSessionRow = new Row({
|
||||
icon: 'activesessions',
|
||||
title: 'Active Sessions',
|
||||
subtitle: '3 devices',
|
||||
subtitle: 'Loading...',
|
||||
clickable: () => {
|
||||
new AppActiveSessionsTab(this.slider).open();
|
||||
const tab = new AppActiveSessionsTab(this.slider);
|
||||
tab.authorizations = authorizations;
|
||||
tab.open();
|
||||
}
|
||||
});
|
||||
activeSessionRow.freezed = true;
|
||||
|
||||
section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionRow.container);
|
||||
this.scrollable.append(section.container);
|
||||
@ -76,7 +80,15 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
twoFactorRow.subtitle.innerText = state.pFlags.has_password ? 'On' : 'Off';
|
||||
twoFactorRow.freezed = false;
|
||||
|
||||
console.log('password state', state);
|
||||
//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);
|
||||
});
|
||||
}
|
||||
|
||||
@ -149,7 +161,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
});
|
||||
}
|
||||
|
||||
container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container,/* callRow.container, */linkAccountRow.container, groupChatsAddRow.container);
|
||||
container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, callRow.container, linkAccountRow.container, groupChatsAddRow.container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,13 +206,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-menu" id="dialogs-contextmenu">
|
||||
<div class="btn-menu-item menu-unread tgico rp"><div></div></div>
|
||||
<div class="btn-menu-item menu-pin tgico rp"><div></div></div>
|
||||
<div class="btn-menu-item menu-mute tgico rp"><div></div></div>
|
||||
<div class="btn-menu-item menu-archive tgico rp"><div></div></div>
|
||||
<div class="btn-menu-item menu-delete tgico-delete danger rp"><div></div></div>
|
||||
</div>
|
||||
<div class="emoji-dropdown" id="emoji-dropdown" style="display: none;">
|
||||
<div class="emoji-container">
|
||||
<div class="tabs-container">
|
||||
|
@ -145,9 +145,6 @@
|
||||
height: 56px;
|
||||
cursor: pointer !important;
|
||||
pointer-events: all !important;
|
||||
background-position: 16px center;
|
||||
background-size: 24px 24px;
|
||||
background-repeat: no-repeat;
|
||||
color: #000;
|
||||
text-transform: none;
|
||||
white-space: nowrap;
|
||||
|
@ -1017,6 +1017,12 @@
|
||||
color: var(--color-text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
&-midtitle, &-subtitle {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-left-section:first-child {
|
||||
|
@ -382,12 +382,12 @@ input, textarea {
|
||||
background: #fed85a;
|
||||
}
|
||||
|
||||
#bubble-contextmenu, #dialogs-contextmenu {
|
||||
position: fixed;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
width: auto;
|
||||
z-index: 4;
|
||||
.contextmenu {
|
||||
position: fixed !important;
|
||||
right: auto !important;
|
||||
bottom: auto !important;
|
||||
width: auto !important;
|
||||
z-index: 4 !important;
|
||||
}
|
||||
|
||||
@keyframes fade-in-opacity {
|
||||
@ -458,6 +458,7 @@ input, textarea {
|
||||
border-radius: $border-radius-medium;
|
||||
animation: fade-in-opacity-fade-out-opacity 3s linear forwards;
|
||||
z-index: 5;
|
||||
max-width: 22.5rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
|
Loading…
x
Reference in New Issue
Block a user