session management in settings

This commit is contained in:
antelle 2021-04-25 18:08:16 +02:00
parent 47153e41d3
commit 9826965803
No known key found for this signature in database
GPG Key ID: 63C9777AAB7C563C
7 changed files with 140 additions and 5 deletions

View File

@ -216,6 +216,20 @@ const BrowserExtensionConnector = {
}
this.sendSocketResult(socketId, result);
},
get sessions() {
return ProtocolImpl.sessions;
},
terminateConnection(connectionId) {
connectionId = +connectionId;
if (Launcher) {
const { ipcRenderer } = Launcher.electron();
ipcRenderer.invoke('browserExtensionConnectorCloseSocket', connectionId);
} else {
ProtocolImpl.deleteConnection(connectionId);
}
}
};

View File

@ -183,10 +183,13 @@ function checkContentRequestPermissions(request) {
clearTimeout(inactivityTimer);
RuntimeDataModel.extensionConnectConfig = extensionConnectView.config;
client.permissions = extensionConnectView.config;
Events.emit('browser-extension-sessions-changed');
resolve();
},
cancel: () => {
client.permissionsDenied = true;
clearTimeout(inactivityTimer);
Events.emit('browser-extension-sessions-changed');
reject(makeError(Errors.userRejected));
}
});
@ -242,7 +245,13 @@ const ProtocolHandlers = {
const keys = tweetnaclBox.keyPair();
publicKey = kdbxweb.ByteUtils.base64ToBytes(publicKey);
connectedClients.set(clientId, { connection, publicKey, version, keys });
const stats = {
connectedDate: new Date()
};
connectedClients.set(clientId, { connection, publicKey, version, keys, stats });
Events.emit('browser-extension-sessions-changed');
logger.info('New client key created', clientId, version);
@ -420,15 +429,22 @@ const ProtocolImpl = {
},
cleanup() {
const wasNotEmpty = connectedClients.size;
connectedClients.clear();
if (wasNotEmpty) {
Events.emit('browser-extension-sessions-changed');
}
},
deleteConnection(connectionId) {
for (const client of connectedClients.values()) {
for (const [clientId, client] of connectedClients.entries()) {
if (client.connection.connectionId === connectionId) {
connectedClients.delete(client);
connectedClients.delete(clientId);
}
}
Events.emit('browser-extension-sessions-changed');
},
errorToResponse(e, request) {
@ -449,6 +465,22 @@ const ProtocolImpl = {
} catch (e) {
return this.errorToResponse(e, request);
}
},
get sessions() {
return [...connectedClients.entries()]
.map(([clientId, client]) => ({
clientId,
connectionId: client.connection.connectionId,
appName: client.connection.appName,
extensionName: client.connection.extensionName,
connectedDate: client.stats.connectedDate,
passwordsRead: client.stats.passwordsRead,
passwordsWritten: client.stats.passwordsWritten,
permissions: client.permissions,
permissionsDenied: client.permissionsDenied
}))
.sort((x, y) => y.connectedDate - x.connectedDate);
}
};

View File

@ -657,6 +657,17 @@
"setBrowserExtensionKPXCWarnHeader": "{} will stop working",
"setBrowserExtensionKPXCWarnBody1": "Unfortunately it's not possible to connect one extension to several apps. If you connect the extension to KeeWeb, we'll overwrite its app association, which means that integration with {} will stop working. Even if you uncheck this checkbox, the association with {} won't be restored. To make it work again, configure browser integration in {} settings.",
"setBrowserExtensionKPXCWarnBody2": "Configure the extension to use KeeWeb?",
"setBrowserSessions": "Sessions",
"setBrowserSessionsEmpty": "No connected sessions.",
"setBrowserSessionsIntro": "These extensions are now connected to KeeWeb.",
"setBrowserSessionsActiveTooltip": "Active session",
"setBrowserSessionsActiveText": "This session is active. It can exchange data with KeeWeb based on the following permissions:",
"setBrowserSessionsInactiveTooltip": "Inactive session",
"setBrowserSessionsInactiveText": "This session is inactive. The extension is connected to KeeWeb, however, it hasn't tried to exchange data. When the extension requests anything, you will be able to choose what you want to share.",
"setBrowserSessionsDeniedTooltip": "Access denied",
"setBrowserSessionsDeniedText": "This session is inactive. The extension is connected to KeeWeb, however, you denied access to data.",
"setBrowserConnectedDate": "Connected",
"setBrowserTerminateSession": "Terminate this session",
"setDevicesTitle": "Devices",
"setDevicesEnableUsb": "Enable interaction with USB devices",

View File

@ -1,3 +1,4 @@
import { Events } from 'framework/events';
import { View } from 'framework/views/view';
import template from 'templates/settings/settings-browser.hbs';
import { Features } from 'util/features';
@ -11,20 +12,32 @@ import {
SupportedExtensions
} from 'comp/extension/browser-extension-connector';
import { Alerts } from 'comp/ui/alerts';
import { DateFormat } from 'comp/i18n/date-format';
class SettingsBrowserView extends View {
template = template;
events = {
'change .check-enable-for-browser': 'changeEnableForBrowser',
'change .settings__browser-focus-if-locked': 'changeFocusIfLocked'
'change .settings__browser-focus-if-locked': 'changeFocusIfLocked',
'click .settings__browser-btn-terminate-session': 'terminateSession'
};
constructor(model, options) {
super(model, options);
this.listenTo(Events, 'browser-extension-sessions-changed', this.render);
}
render() {
const data = {
desktop: Features.isDesktop,
icon: Features.browserIcon,
focusIfLocked: AppSettingsModel.extensionFocusIfLocked
focusIfLocked: AppSettingsModel.extensionFocusIfLocked,
sessions: BrowserExtensionConnector.sessions.map((session) => ({
...session,
connectedDate: DateFormat.dtStr(session.connectedDate)
}))
};
if (Features.isDesktop) {
data.extensionNames = ['KeeWeb Connect', 'KeePassXC-Browser'];
@ -103,6 +116,11 @@ class SettingsBrowserView extends View {
AppSettingsModel.extensionFocusIfLocked = e.target.checked;
this.render();
}
terminateSession(e) {
const connectionId = e.target.dataset.connectionId;
BrowserExtensionConnector.terminateConnection(connectionId);
}
}
export { SettingsBrowserView };

View File

@ -314,6 +314,17 @@
padding: $base-padding;
}
}
&-extension-status {
display: inline-block;
width: 0;
height: 0;
border-radius: 100%;
border: 5px solid;
margin-right: 0.2em;
}
&-session-buttons {
margin-top: $base-padding-h;
}
}
&__donate-btn {
background: #fff;

View File

@ -73,4 +73,47 @@
{{#if focusIfLocked}}checked{{/if}} />
<label for="settings__browser-focus-if-locked">{{res 'setBrowserFocusIfLocked'}}</label>
</div>
<h2>{{res 'setBrowserSessions'}}</h2>
{{#if sessions.length}}
<p>{{res 'setBrowserSessionsIntro'}}</p>
{{#each sessions as |session|}}
<h3>
<div class="settings__browser-extension-status
{{#if session.permissions}}
green-color
{{else if session.permissionsDenied}}
red-color
{{else}}
muted-color
{{/if}}"
title="
{{~#if session.permissions~}}
{{res 'setBrowserSessionsActiveTooltip'}}
{{~else if session.permissionsDenied~}}
{{res 'setBrowserSessionsDeniedTooltip'}}
{{~else~}}
{{res 'setBrowserSessionsInactiveTooltip'}}
{{/if}}"
></div>
{{session.extensionName}} ({{session.appName}})
</h3>
<p>{{res 'setBrowserConnectedDate'}}: {{session.connectedDate}}</p>
{{#if session.permissions}}
{{res 'setBrowserSessionsActiveText'}}
{{else if session.permissionsDenied}}
{{res 'setBrowserSessionsDeniedText'}}
{{else}}
{{res 'setBrowserSessionsInactiveText'}}
{{/if}}
<div class="settings__browser-session-buttons">
<button class="btn btn-error settings__browser-btn-terminate-session"
data-connection-id="{{session.connectionId}}"
>{{res 'setBrowserTerminateSession'}}</button>
</div>
{{/each}}
{{else}}
<p>{{res 'setBrowserSessionsEmpty'}}</p>
{{/if}}
</div>

View File

@ -12,6 +12,7 @@ ipcMain.handle('browserExtensionConnectorStop', browserExtensionConnectorStop);
ipcMain.handle('browserExtensionConnectorEnable', browserExtensionConnectorEnable);
ipcMain.handle('browserExtensionConnectorSocketResult', browserExtensionConnectorSocketResult);
ipcMain.handle('browserExtensionConnectorSocketEvent', browserExtensionConnectorSocketEvent);
ipcMain.handle('browserExtensionConnectorCloseSocket', browserExtensionConnectorCloseSocket);
const logger = new Logger('browser-extension-connector');
@ -105,6 +106,11 @@ function browserExtensionConnectorSocketEvent(e, data) {
sendEventToAllSockets(data);
}
function browserExtensionConnectorCloseSocket(e, socketId) {
const socket = connectedSockets.get(socketId);
socket?.destroy();
}
function getBrowserExtensionSocketName(config) {
const { username, uid } = os.userInfo();
if (process.platform === 'darwin') {