mirror of
https://github.com/CringeStudios/element-desktop.git
synced 2025-01-18 23:44:59 +01:00
parent
d1f488a094
commit
e50e04c507
54
src/@types/keytar.d.ts
vendored
Normal file
54
src/@types/keytar.d.ts
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
// Based on https://github.com/atom/node-keytar/blob/master/keytar.d.ts because keytar is a hak-dependency and not a normal one
|
||||
// Definitions by: Milan Burda <https://github.com/miniak>, Brendan Forster <https://github.com/shiftkey>, Hari Juturu <https://github.com/juturu>
|
||||
// Adapted from DefinitelyTyped: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/keytar/index.d.ts
|
||||
|
||||
declare module "keytar" {
|
||||
/**
|
||||
* Get the stored password for the service and account.
|
||||
*
|
||||
* @param service The string service name.
|
||||
* @param account The string account name.
|
||||
*
|
||||
* @returns A promise for the password string.
|
||||
*/
|
||||
export function getPassword(service: string, account: string): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* Add the password for the service and account to the keychain.
|
||||
*
|
||||
* @param service The string service name.
|
||||
* @param account The string account name.
|
||||
* @param password The string password.
|
||||
*
|
||||
* @returns A promise for the set password completion.
|
||||
*/
|
||||
export function setPassword(service: string, account: string, password: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Delete the stored password for the service and account.
|
||||
*
|
||||
* @param service The string service name.
|
||||
* @param account The string account name.
|
||||
*
|
||||
* @returns A promise for the deletion status. True on success.
|
||||
*/
|
||||
export function deletePassword(service: string, account: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Find a password for the service in the keychain.
|
||||
*
|
||||
* @param service The string service name.
|
||||
*
|
||||
* @returns A promise for the password string.
|
||||
*/
|
||||
export function findPassword(service: string): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* Find all accounts and passwords for `service` in the keychain.
|
||||
*
|
||||
* @param service The string service name.
|
||||
*
|
||||
* @returns A promise for the array of found credentials.
|
||||
*/
|
||||
export function findCredentials(service: string): Promise<Array<{ account: string, password: string}>>;
|
||||
}
|
145
src/@types/matrix-seshat.d.ts
vendored
Normal file
145
src/@types/matrix-seshat.d.ts
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
declare module "matrix-seshat" {
|
||||
interface IConfig {
|
||||
language?: string;
|
||||
passphrase?: string;
|
||||
}
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
interface IMatrixEvent {
|
||||
event_id: string;
|
||||
sender: string;
|
||||
room_id: string;
|
||||
origin_server_ts: number;
|
||||
content: Record<string, any>;
|
||||
}
|
||||
|
||||
interface IMatrixProfile {
|
||||
displayname?: string;
|
||||
avatar_url?: string;
|
||||
}
|
||||
|
||||
interface ISearchArgs {
|
||||
searchTerm: number;
|
||||
limit: number;
|
||||
before_limit: number;
|
||||
after_limit: number;
|
||||
order_by_recency: boolean;
|
||||
next_batch?: string;
|
||||
}
|
||||
|
||||
interface ISearchContext {
|
||||
events_before: IMatrixEvent[];
|
||||
events_after: IMatrixEvent[];
|
||||
profile_info: { [userId: string]: IMatrixProfile };
|
||||
}
|
||||
|
||||
interface ISearchResult {
|
||||
next_batch: string;
|
||||
count: number;
|
||||
results: Array<{
|
||||
rank: number;
|
||||
result: IMatrixEvent;
|
||||
context: ISearchContext;
|
||||
}>;
|
||||
}
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
interface ICheckpoint {
|
||||
roomId: string;
|
||||
token: string;
|
||||
fullCrawl: boolean;
|
||||
direction: "b" | "f";
|
||||
}
|
||||
|
||||
interface IDatabaseStats {
|
||||
size: number;
|
||||
eventCount: number;
|
||||
roomCount: number;
|
||||
}
|
||||
|
||||
interface ILoadArgs {
|
||||
roomId: string;
|
||||
limit: number;
|
||||
fromEvent: string;
|
||||
direction: "b" | "f";
|
||||
}
|
||||
|
||||
interface ILoadResult {
|
||||
event: IMatrixEvent;
|
||||
matrixProfile: IMatrixProfile;
|
||||
}
|
||||
|
||||
export class Seshat {
|
||||
constructor(path: string, config?: IConfig);
|
||||
public addEvent(matrixEvent: IMatrixEvent, profile?: IMatrixProfile): void;
|
||||
public deleteEvent(eventId: string): Promise<boolean>;
|
||||
public commit(force?: boolean): Promise<number>;
|
||||
public commitSync(wait?: boolean, force?: boolean): number;
|
||||
public reload(): void;
|
||||
public search(args: ISearchArgs): Promise<ISearchResult>;
|
||||
public searchSync(
|
||||
term: string,
|
||||
limit?: number,
|
||||
beforeLimit?: number,
|
||||
afterLimit?: number,
|
||||
orderByRecency?: boolean,
|
||||
): ISearchResult;
|
||||
public addHistoricEventsSync(
|
||||
events: IMatrixEvent[],
|
||||
newCheckpoint?: ICheckpoint,
|
||||
oldCheckpoint?: ICheckpoint,
|
||||
): boolean;
|
||||
public addHistoricEvents(
|
||||
events: IMatrixEvent[],
|
||||
newCheckpoint?: ICheckpoint,
|
||||
oldCheckpoint?: ICheckpoint,
|
||||
): Promise<boolean>;
|
||||
public addCrawlerCheckpoint(checkpoint: ICheckpoint): Promise<void>;
|
||||
public removeCrawlerCheckpoint(checkpoint: ICheckpoint): Promise<void>;
|
||||
public loadCheckpoints(): Promise<ICheckpoint[]>;
|
||||
public getSize(): Promise<number>;
|
||||
public getStats(): Promise<IDatabaseStats>;
|
||||
public delete(): Promise<void>;
|
||||
public shutdown(): Promise<void>;
|
||||
public changePassphrase(newPassphrase: string): Promise<void>;
|
||||
public isEmpty(): Promise<boolean>;
|
||||
public isRoomIndexed(roomId: string): Promise<boolean>;
|
||||
public getUserVersion(): Promise<number>;
|
||||
public setUserVersion(version: number): Promise<void>;
|
||||
public loadFileEvents(args: ILoadArgs): Promise<ILoadResult[]>;
|
||||
}
|
||||
|
||||
interface IRecoveryInfo {
|
||||
totalEvents: number;
|
||||
reindexedEvents: number;
|
||||
done: number;
|
||||
}
|
||||
|
||||
export class SeshatRecovery {
|
||||
constructor(path: string, config?: IConfig);
|
||||
public info(): IRecoveryInfo;
|
||||
public getUserVersion(): Promise<number>;
|
||||
public shutdown(): Promise<void>;
|
||||
public reindex(): Promise<void>;
|
||||
}
|
||||
|
||||
export class ReindexError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
}
|
@ -39,18 +39,26 @@ import crypto from "crypto";
|
||||
import { URL } from "url";
|
||||
import minimist from "minimist";
|
||||
|
||||
import type * as Keytar from "keytar"; // Hak dependency type
|
||||
import type {
|
||||
Seshat as SeshatType,
|
||||
SeshatRecovery as SeshatRecoveryType,
|
||||
ReindexError as ReindexErrorType,
|
||||
} from "matrix-seshat"; // Hak dependency type
|
||||
import * as tray from "./tray";
|
||||
import { buildMenuTemplate } from './vectormenu';
|
||||
import webContentsHandler from './webcontents-handler';
|
||||
import * as updater from './updater';
|
||||
import { getProfileFromDeeplink, protocolInit, recordSSOSession } from './protocol';
|
||||
import { _t, AppLocalization } from './language-helper';
|
||||
import Input = Electron.Input;
|
||||
import IpcMainEvent = Electron.IpcMainEvent;
|
||||
|
||||
const argv = minimist(process.argv, {
|
||||
alias: { help: "h" },
|
||||
});
|
||||
|
||||
let keytar;
|
||||
let keytar: typeof Keytar;
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
keytar = require('keytar');
|
||||
@ -63,9 +71,9 @@ try {
|
||||
}
|
||||
|
||||
let seshatSupported = false;
|
||||
let Seshat;
|
||||
let SeshatRecovery;
|
||||
let ReindexError;
|
||||
let Seshat: typeof SeshatType;
|
||||
let SeshatRecovery: typeof SeshatRecoveryType;
|
||||
let ReindexError: typeof ReindexErrorType;
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
@ -84,13 +92,18 @@ try {
|
||||
|
||||
// Things we need throughout the file but need to be created
|
||||
// async to are initialised in setupGlobals()
|
||||
let asarPath;
|
||||
let resPath;
|
||||
let vectorConfig;
|
||||
let iconPath;
|
||||
let trayConfig;
|
||||
let launcher;
|
||||
let appLocalization;
|
||||
let asarPath: string;
|
||||
let resPath: string;
|
||||
let iconPath: string;
|
||||
|
||||
let vectorConfig: Record<string, any>;
|
||||
let trayConfig: {
|
||||
// eslint-disable-next-line camelcase
|
||||
icon_path: string;
|
||||
brand: string;
|
||||
};
|
||||
let launcher: AutoLaunch;
|
||||
let appLocalization: AppLocalization;
|
||||
|
||||
if (argv["help"]) {
|
||||
console.log("Options:");
|
||||
@ -108,12 +121,12 @@ if (argv["help"]) {
|
||||
// Electron creates the user data directory (with just an empty 'Dictionaries' directory...)
|
||||
// as soon as the app path is set, so pick a random path in it that must exist if it's a
|
||||
// real user data directory.
|
||||
function isRealUserDataDir(d) {
|
||||
function isRealUserDataDir(d: string): boolean {
|
||||
return fs.existsSync(path.join(d, 'IndexedDB'));
|
||||
}
|
||||
|
||||
// check if we are passed a profile in the SSO callback url
|
||||
let userDataPath;
|
||||
let userDataPath: string;
|
||||
|
||||
const userDataPathInProtocol = getProfileFromDeeplink(argv["_"]);
|
||||
if (userDataPathInProtocol) {
|
||||
@ -143,7 +156,7 @@ if (userDataPathInProtocol) {
|
||||
}
|
||||
app.setPath('userData', userDataPath);
|
||||
|
||||
async function tryPaths(name, root, rawPaths) {
|
||||
async function tryPaths(name: string, root: string, rawPaths: string[]): Promise<string> {
|
||||
// Make everything relative to root
|
||||
const paths = rawPaths.map(p => path.join(root, p));
|
||||
|
||||
@ -162,7 +175,7 @@ async function tryPaths(name, root, rawPaths) {
|
||||
}
|
||||
|
||||
// Find the webapp resources and set up things that require them
|
||||
async function setupGlobals() {
|
||||
async function setupGlobals(): Promise<void> {
|
||||
// find the webapp asar.
|
||||
asarPath = await tryPaths("webapp", __dirname, [
|
||||
// If run from the source checkout, this will be in the directory above
|
||||
@ -245,9 +258,9 @@ async function setupGlobals() {
|
||||
});
|
||||
}
|
||||
|
||||
async function moveAutoLauncher() {
|
||||
async function moveAutoLauncher(): Promise<void> {
|
||||
// Look for an auto-launcher under 'Riot' and if we find one, port it's
|
||||
// enabled/disbaledp-ness over to the new 'Element' launcher
|
||||
// enabled/disabled-ness over to the new 'Element' launcher
|
||||
if (!vectorConfig.brand || vectorConfig.brand === 'Element') {
|
||||
const oldLauncher = new AutoLaunch({
|
||||
name: 'Riot',
|
||||
@ -274,18 +287,18 @@ const store = new Store<{
|
||||
disableHardwareAcceleration?: boolean;
|
||||
}>({ name: "electron-config" });
|
||||
|
||||
let eventIndex = null;
|
||||
let eventIndex: SeshatType = null;
|
||||
|
||||
let mainWindow = null;
|
||||
let mainWindow: BrowserWindow = null;
|
||||
global.appQuitting = false;
|
||||
|
||||
const exitShortcuts = [
|
||||
const exitShortcuts: Array<(input: Input, platform: string) => boolean> = [
|
||||
(input, platform) => platform !== 'darwin' && input.alt && input.key.toUpperCase() === 'F4',
|
||||
(input, platform) => platform !== 'darwin' && input.control && input.key.toUpperCase() === 'Q',
|
||||
(input, platform) => platform === 'darwin' && input.meta && input.key.toUpperCase() === 'Q',
|
||||
];
|
||||
|
||||
const warnBeforeExit = (event, input) => {
|
||||
const warnBeforeExit = (event: Event, input: Input): void => {
|
||||
const shouldWarnBeforeExit = store.get('warnBeforeExit', true);
|
||||
const exitShortcutPressed =
|
||||
input.type === 'keyDown' && exitShortcuts.some(shortcutFn => shortcutFn(input, process.platform));
|
||||
@ -305,14 +318,14 @@ const warnBeforeExit = (event, input) => {
|
||||
}
|
||||
};
|
||||
|
||||
const deleteContents = async (p) => {
|
||||
const deleteContents = async (p: string): Promise<void> => {
|
||||
for (const entry of await afs.readdir(p)) {
|
||||
const curPath = path.join(p, entry);
|
||||
await afs.unlink(curPath);
|
||||
}
|
||||
};
|
||||
|
||||
async function randomArray(size) {
|
||||
async function randomArray(size: number): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
crypto.randomBytes(size, (err, buf) => {
|
||||
if (err) {
|
||||
@ -330,12 +343,12 @@ async function randomArray(size) {
|
||||
// no other way to catch this error).
|
||||
// Assuming we generally run from the console when developing,
|
||||
// this is far preferable.
|
||||
process.on('uncaughtException', function(error) {
|
||||
process.on('uncaughtException', function(error: Error): void {
|
||||
console.log('Unhandled exception', error);
|
||||
});
|
||||
|
||||
let focusHandlerAttached = false;
|
||||
ipcMain.on('setBadgeCount', function(ev, count) {
|
||||
ipcMain.on('setBadgeCount', function(_ev: IpcMainEvent, count: number): void {
|
||||
if (process.platform !== 'win32') {
|
||||
// only set badgeCount on Mac/Linux, the docs say that only those platforms support it but turns out Electron
|
||||
// has some Windows support too, and in some Windows environments this leads to two badges rendering atop
|
||||
@ -347,7 +360,7 @@ ipcMain.on('setBadgeCount', function(ev, count) {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('loudNotification', function() {
|
||||
ipcMain.on('loudNotification', function(): void {
|
||||
if (process.platform === 'win32' && mainWindow && !mainWindow.isFocused() && !focusHandlerAttached) {
|
||||
mainWindow.flashFrame(true);
|
||||
mainWindow.once('focus', () => {
|
||||
@ -358,8 +371,8 @@ ipcMain.on('loudNotification', function() {
|
||||
}
|
||||
});
|
||||
|
||||
let powerSaveBlockerId = null;
|
||||
ipcMain.on('app_onAction', function(ev, payload) {
|
||||
let powerSaveBlockerId: number = null;
|
||||
ipcMain.on('app_onAction', function(_ev: IpcMainEvent, payload) {
|
||||
switch (payload.action) {
|
||||
case 'call_state':
|
||||
if (powerSaveBlockerId !== null && powerSaveBlocker.isStarted(powerSaveBlockerId)) {
|
||||
@ -376,11 +389,11 @@ ipcMain.on('app_onAction', function(ev, payload) {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('ipcCall', async function(ev, payload) {
|
||||
ipcMain.on('ipcCall', async function(_ev: IpcMainEvent, payload) {
|
||||
if (!mainWindow) return;
|
||||
|
||||
const args = payload.args || [];
|
||||
let ret;
|
||||
let ret: any;
|
||||
|
||||
switch (payload.name) {
|
||||
case 'getUpdateFeedUrl':
|
||||
@ -542,7 +555,7 @@ ipcMain.on('ipcCall', async function(ev, payload) {
|
||||
});
|
||||
|
||||
const seshatDefaultPassphrase = "DEFAULT_PASSPHRASE";
|
||||
async function getOrCreatePassphrase(key) {
|
||||
async function getOrCreatePassphrase(key: string): Promise<string> {
|
||||
if (keytar) {
|
||||
try {
|
||||
const storedPassphrase = await keytar.getPassword("element.io", key);
|
||||
@ -561,7 +574,7 @@ async function getOrCreatePassphrase(key) {
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.on('seshat', async function(ev, payload) {
|
||||
ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
|
||||
if (!mainWindow) return;
|
||||
|
||||
const sendError = (id, e) => {
|
||||
@ -576,7 +589,7 @@ ipcMain.on('seshat', async function(ev, payload) {
|
||||
};
|
||||
|
||||
const args = payload.args || [];
|
||||
let ret;
|
||||
let ret: any;
|
||||
|
||||
switch (payload.name) {
|
||||
case 'supportsEventIndexing':
|
||||
@ -913,7 +926,7 @@ app.on('ready', async () => {
|
||||
target[target.length - 1] = 'index.html';
|
||||
}
|
||||
|
||||
let baseDir;
|
||||
let baseDir: string;
|
||||
if (target[1] === 'webapp') {
|
||||
baseDir = asarPath;
|
||||
} else {
|
||||
@ -1048,7 +1061,7 @@ app.on('activate', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
|
||||
function beforeQuit() {
|
||||
function beforeQuit(): void {
|
||||
global.appQuitting = true;
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('before-quit');
|
||||
|
@ -80,7 +80,7 @@ export function recordSSOSession(sessionID: string): void {
|
||||
writeStore(store);
|
||||
}
|
||||
|
||||
export function getProfileFromDeeplink(args): string | undefined {
|
||||
export function getProfileFromDeeplink(args: string[]): string | undefined {
|
||||
// check if we are passed a profile in the SSO callback url
|
||||
const deeplinkUrl = args.find(arg => arg.startsWith(PROTOCOL + '//'));
|
||||
if (deeplinkUrl && deeplinkUrl.includes(SEARCH_PARAM)) {
|
||||
|
Loading…
Reference in New Issue
Block a user