chore: upgrade eslint and prettier (#2376)
* chore: upgrade eslint and prettier * chore: add restrict-template-expressions
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "*",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint": "*",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^29.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
|
||||
@@ -19,7 +19,10 @@ import { UserUpdateResponse } from '../../Response/User/UserUpdateResponse'
|
||||
export class UserApiService implements UserApiServiceInterface {
|
||||
private operationsInProgress: Map<UserApiOperations, boolean>
|
||||
|
||||
constructor(private userServer: UserServerInterface, private userRequestServer: UserRequestServerInterface) {
|
||||
constructor(
|
||||
private userServer: UserServerInterface,
|
||||
private userRequestServer: UserRequestServerInterface,
|
||||
) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,11 @@ export class HttpService implements HttpServiceInterface {
|
||||
|
||||
private requestHandler: RequestHandlerInterface
|
||||
|
||||
constructor(private environment: Environment, private appVersion: string, private snjsVersion: string) {
|
||||
constructor(
|
||||
private environment: Environment,
|
||||
private appVersion: string,
|
||||
private snjsVersion: string,
|
||||
) {
|
||||
this.requestHandler = new FetchRequestHandler(this.snjsVersion, this.appVersion, this.environment)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"babel-loader": "^9.1.0",
|
||||
"copy-webpack-plugin": "11.0.0",
|
||||
"eslint": "*",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-prettier": "^8.9.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "*",
|
||||
"web-ext": "^7.5.0",
|
||||
|
||||
@@ -9,7 +9,7 @@ export const RuntimeMessageTypes = {
|
||||
CaptureVisibleTab: 'capture-visible-tab',
|
||||
} as const
|
||||
|
||||
export type RuntimeMessageType = typeof RuntimeMessageTypes[keyof typeof RuntimeMessageTypes]
|
||||
export type RuntimeMessageType = (typeof RuntimeMessageTypes)[keyof typeof RuntimeMessageTypes]
|
||||
|
||||
type MessagesWithClipPayload = typeof RuntimeMessageTypes.OpenPopupWithSelection
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
dist/
|
||||
app/dist/
|
||||
test/data/tmp/
|
||||
CHANGELOG.md
|
||||
CHANGELOG.md
|
||||
app/grantLinuxPasswordsAccess.html
|
||||
@@ -1,95 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Standard Notes</title>
|
||||
<link rel="stylesheet" media="all" href="web/app.css" />
|
||||
<link rel="stylesheet" media="all" href="stylesheets/renderer.css" />
|
||||
</head>
|
||||
|
||||
<body class="main-ui">
|
||||
<div class="sk-modal">
|
||||
<div class="challenge-modal sk-modal-content" style="margin: 2rem">
|
||||
<div class="sn-component">
|
||||
<div class="sk-panel">
|
||||
<div class="sk-panel-header">
|
||||
<div class="sk-panel-header-title capitalize">Password service access</div>
|
||||
</div>
|
||||
<div class="sk-panel-content" style="padding-bottom: 2rem">
|
||||
<h1 class="sk-h1">Choose how you want Standard Notes to store your account keys</h1>
|
||||
<p class="sk-p">
|
||||
Standard Notes can either use your operating system's password manager or its own local storage
|
||||
facility.
|
||||
</p>
|
||||
<p class="sk-p">
|
||||
<strong>Standard Notes currently does not have access to your system password service.</strong>
|
||||
If you grant it access, you must quit the app for the change to come into effect.
|
||||
</p>
|
||||
<div class="sk-panel-row">
|
||||
<div class="sk-button-group">
|
||||
<button class="sk-button info" id="quit-button">
|
||||
<div class="sk-label capitalize">Use password service (quit)</div>
|
||||
</button>
|
||||
<button class="sk-button neutral capitalize" id="use-storage-button">
|
||||
<div class="sk-label">Use local storage (continue)</div>
|
||||
</button>
|
||||
</div>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Standard Notes</title>
|
||||
<link rel="stylesheet" media="all" href="web/app.css" />
|
||||
<link rel="stylesheet" media="all" href="stylesheets/renderer.css" />
|
||||
</head>
|
||||
|
||||
<body class="main-ui">
|
||||
<div class="sk-modal">
|
||||
<div class="challenge-modal sk-modal-content" style="margin: 2rem">
|
||||
<div class="sn-component">
|
||||
<div class="sk-panel">
|
||||
<div class="sk-panel-header">
|
||||
<div class="sk-panel-header-title capitalize">Password service access</div>
|
||||
</div>
|
||||
<div class="sk-panel-content" style="padding-bottom: 2rem">
|
||||
<h1 class="sk-h1">Choose how you want Standard Notes to store your account keys</h1>
|
||||
<p class="sk-p">
|
||||
Standard Notes can either use your operating system's password manager or its own local storage
|
||||
facility.
|
||||
</p>
|
||||
<p class="sk-p">
|
||||
<strong>Standard Notes currently does not have access to your system password service.</strong>
|
||||
If you grant it access, you must quit the app for the change to come into effect.
|
||||
</p>
|
||||
<div class="sk-panel-row">
|
||||
<div class="sk-button-group">
|
||||
<button class="sk-button info" id="quit-button">
|
||||
<div class="sk-label capitalize">Use password service (quit)</div>
|
||||
</button>
|
||||
<button class="sk-button neutral capitalize" id="use-storage-button">
|
||||
<div class="sk-label">Use local storage (continue)</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="sk-panel-row"></div>
|
||||
<a class="sk-a capitalize" id="learn-more">Learn more</a>
|
||||
<div style="display: none" id="more-info">
|
||||
<div class="sk-panel-section">
|
||||
<h1 class="sk-h1">What's the difference?</h1>
|
||||
<p class="sk-p">
|
||||
Using local storage, your account keys may be more easily accessible by third-party programs, unlike
|
||||
in your password manager which has additional protections built-in.
|
||||
</p>
|
||||
<p class="sk-p">
|
||||
In either cases, the strongest way to protect your account keys is to use a strong passcode, which
|
||||
will be used to encrypt your keys and prevent any software or operating system from reading them.
|
||||
<strong> If you plan on setting a passcode, you can safely use local storage. </strong>
|
||||
</p>
|
||||
<div class="sk-panel-row"></div>
|
||||
<h2 class="sk-h2">Granting Standard Notes access to your system password service</h2>
|
||||
<p class="sk-p">
|
||||
Note that
|
||||
<strong>
|
||||
granting access to your system password service will allow Standard Notes to read, write, and
|
||||
delete <em>any</em> of your saved passwords.
|
||||
</strong>
|
||||
Standard Notes will never use this privilege to do anything more than reading and writing to its own
|
||||
entry.
|
||||
</p>
|
||||
<ol>
|
||||
<li class="sk-li">Quit Standard Notes</li>
|
||||
<li class="sk-li">Open your software store (Ubuntu Software Center/Snap Store)</li>
|
||||
<li class="sk-li">In your installed apps list, click on Standard Notes</li>
|
||||
<li class="sk-li">Look for a <em>Permissions</em> button</li>
|
||||
<li class="sk-li">
|
||||
Make sure the permission associated with reading and writing passwords is checked
|
||||
</li>
|
||||
<li class="sk-li">Open Standard Notes again</li>
|
||||
</ol>
|
||||
<h2 class="sk-h2">
|
||||
Granting Standard Notes access to your system password service from the command line
|
||||
</h2>
|
||||
<p class="sk-p">
|
||||
Run the following command:<br />
|
||||
<code>snap connect standard-notes:password-manager-service</code>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<em>
|
||||
Note: Password Service may also be referred to as keyring, saved passwords, stored passwords,
|
||||
password manager, passwords, or secrets, depending on your Linux configuration.
|
||||
</em>
|
||||
</div>
|
||||
<div class="sk-panel-row"></div>
|
||||
<a class="sk-a capitalize" id="learn-more">Learn more</a>
|
||||
<div style="display: none" id="more-info">
|
||||
<div class="sk-panel-section">
|
||||
<h1 class="sk-h1">What's the difference?</h1>
|
||||
<p class="sk-p">
|
||||
Using local storage, your account keys may be more easily accessible by third-party programs, unlike
|
||||
in your password manager which has additional protections built-in.
|
||||
</p>
|
||||
<p class="sk-p">
|
||||
In either cases, the strongest way to protect your account keys is to use a strong passcode, which
|
||||
will be used to encrypt your keys and prevent any software or operating system from reading them.
|
||||
<strong> If you plan on setting a passcode, you can safely use local storage. </strong>
|
||||
</p>
|
||||
<div class="sk-panel-row"></div>
|
||||
<h2 class="sk-h2">Granting Standard Notes access to your system password service</h2>
|
||||
<p class="sk-p">
|
||||
Note that
|
||||
<strong>
|
||||
granting access to your system password service will allow Standard Notes to read, write, and
|
||||
delete <em>any</em> of your saved passwords.
|
||||
</strong>
|
||||
Standard Notes will never use this privilege to do anything more than reading and writing to its own
|
||||
entry.
|
||||
</p>
|
||||
<ol>
|
||||
<li class="sk-li">Quit Standard Notes</li>
|
||||
<li class="sk-li">Open your software store (Ubuntu Software Center/Snap Store)</li>
|
||||
<li class="sk-li">In your installed apps list, click on Standard Notes</li>
|
||||
<li class="sk-li">Look for a <em>Permissions</em> button</li>
|
||||
<li class="sk-li">
|
||||
Make sure the permission associated with reading and writing passwords is checked
|
||||
</li>
|
||||
<li class="sk-li">Open Standard Notes again</li>
|
||||
</ol>
|
||||
<h2 class="sk-h2">
|
||||
Granting Standard Notes access to your system password service from the command line
|
||||
</h2>
|
||||
<p class="sk-p">
|
||||
Run the following command:<br />
|
||||
<code>snap connect standard-notes:password-manager-service</code>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<em>
|
||||
Note: Password Service may also be referred to as keyring, saved passwords, stored passwords,
|
||||
password manager, passwords, or secrets, depending on your Linux configuration.
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -72,6 +72,7 @@ export class FilesManager implements FilesManagerInterface {
|
||||
if (!stat.isDirectory()) {
|
||||
throw new Error('Tried to create a directory where a file of the same ' + `name already exists: ${dirPath}`)
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
if (error.code === FileErrorCodes.FileDoesNotExist) {
|
||||
/**
|
||||
@@ -83,6 +84,7 @@ export class FilesManager implements FilesManagerInterface {
|
||||
/** Now that its parent(s) exist, create the directory */
|
||||
try {
|
||||
await fs.promises.mkdir(dirPath)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
if (error.code === FileErrorCodes.FileAlreadyExists) {
|
||||
/**
|
||||
@@ -257,6 +259,7 @@ export class FilesManager implements FilesManagerInterface {
|
||||
|
||||
try {
|
||||
await this.ensureDirectoryExists(path.dirname(filepath))
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
return tryReject(error)
|
||||
}
|
||||
@@ -299,6 +302,7 @@ export class FilesManager implements FilesManagerInterface {
|
||||
try {
|
||||
await fs.promises.unlink(filePath)
|
||||
break
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
if (error.code === FileErrorCodes.OperationNotPermitted || error.code === FileErrorCodes.DeviceIsBusy) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300))
|
||||
|
||||
@@ -4,7 +4,12 @@ import { downloadData } from './FileNetworking'
|
||||
export class FileDownloader {
|
||||
writeStream: WriteStream
|
||||
|
||||
constructor(private chunkSizes: number[], private valetToken: string, private url: string, filePath: string) {
|
||||
constructor(
|
||||
private chunkSizes: number[],
|
||||
private valetToken: string,
|
||||
private url: string,
|
||||
filePath: string,
|
||||
) {
|
||||
this.writeStream = createWriteStream(filePath, { flags: 'a' })
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,10 @@ export class HomeServerManager implements HomeServerManagerInterface {
|
||||
|
||||
private homeServer?: TempHomeServerInterface
|
||||
|
||||
constructor(private webContents: WebContents, private filesManager: FilesManagerInterface) {}
|
||||
constructor(
|
||||
private webContents: WebContents,
|
||||
private filesManager: FilesManagerInterface,
|
||||
) {}
|
||||
|
||||
async getHomeServerUrl(): Promise<string | undefined> {
|
||||
const homeServerConfiguration = await this.getHomeServerConfigurationObject()
|
||||
|
||||
@@ -17,9 +17,7 @@ import { TrayManager } from '../TrayManager'
|
||||
import { autoUpdatingAvailable } from '../Types/Constants'
|
||||
import { isLinux, isMac } from '../Types/Platforms'
|
||||
import { checkForUpdate, openChangelog, showUpdateInstallationDialog } from '../UpdateManager'
|
||||
import { handleTestMessage } from '../Utils/Testing'
|
||||
import { isDev, isTesting } from '../Utils/Utils'
|
||||
import { MessageType } from './../../../../test/TestIpcMessage'
|
||||
import { isDev } from '../Utils/Utils'
|
||||
import { SpellcheckerManager } from './../SpellcheckerManager'
|
||||
import { MenuManagerInterface } from './MenuManagerInterface'
|
||||
|
||||
@@ -123,42 +121,7 @@ export function createMenuManager({
|
||||
}): MenuManagerInterface {
|
||||
let menu: Menu
|
||||
|
||||
if (isTesting()) {
|
||||
// eslint-disable-next-line no-var
|
||||
var hasReloaded = false
|
||||
// eslint-disable-next-line no-var
|
||||
var hasReloadedTimeout: any
|
||||
handleTestMessage(MessageType.AppMenuItems, () =>
|
||||
menu.items.map((item) => ({
|
||||
label: item.label,
|
||||
role: item.role,
|
||||
submenu: {
|
||||
items: item.submenu?.items?.map((subItem) => ({
|
||||
id: subItem.id,
|
||||
label: subItem.label,
|
||||
})),
|
||||
},
|
||||
})),
|
||||
)
|
||||
handleTestMessage(MessageType.ClickLanguage, (code) => {
|
||||
menu.getMenuItemById(MessageType.ClickLanguage + code)!.click()
|
||||
})
|
||||
handleTestMessage(MessageType.HasReloadedMenu, () => hasReloaded)
|
||||
}
|
||||
|
||||
function reload() {
|
||||
if (isTesting()) {
|
||||
// eslint-disable-next-line block-scoped-var
|
||||
hasReloaded = true
|
||||
// eslint-disable-next-line block-scoped-var
|
||||
clearTimeout(hasReloadedTimeout)
|
||||
// eslint-disable-next-line block-scoped-var
|
||||
hasReloadedTimeout = setTimeout(() => {
|
||||
// eslint-disable-next-line block-scoped-var
|
||||
hasReloaded = false
|
||||
}, 300)
|
||||
}
|
||||
|
||||
menu = Menu.buildFromTemplate([
|
||||
...(isMac() ? [macAppMenu(app.name)] : []),
|
||||
editMenu(spellcheckerManager, reload),
|
||||
@@ -270,7 +233,10 @@ function macAppMenu(appName: string): MenuItemConstructorOptions {
|
||||
}
|
||||
}
|
||||
|
||||
function editMenu(spellcheckerManager: SpellcheckerManager | undefined, reload: () => any): MenuItemConstructorOptions {
|
||||
function editMenu(
|
||||
spellcheckerManager: SpellcheckerManager | undefined,
|
||||
reload: () => void,
|
||||
): MenuItemConstructorOptions {
|
||||
if (isDev()) {
|
||||
/** Check for invalid state */
|
||||
if (!isMac() && spellcheckerManager === undefined) {
|
||||
@@ -323,13 +289,13 @@ function macSpeechMenu(): MenuItemConstructorOptions {
|
||||
}
|
||||
}
|
||||
|
||||
function spellcheckerMenu(spellcheckerManager: SpellcheckerManager, reload: () => any): MenuItemConstructorOptions {
|
||||
function spellcheckerMenu(spellcheckerManager: SpellcheckerManager, reload: () => void): MenuItemConstructorOptions {
|
||||
return {
|
||||
id: MenuId.SpellcheckerLanguages,
|
||||
label: str().spellcheckerLanguages,
|
||||
submenu: spellcheckerManager.languages().map(
|
||||
({ name, code, enabled }): MenuItemConstructorOptions => ({
|
||||
...(isTesting() ? { id: MessageType.ClickLanguage + code } : {}),
|
||||
...{},
|
||||
label: name,
|
||||
type: MenuItemTypes.CheckBox,
|
||||
checked: enabled,
|
||||
@@ -346,7 +312,7 @@ function spellcheckerMenu(spellcheckerManager: SpellcheckerManager, reload: () =
|
||||
}
|
||||
}
|
||||
|
||||
function viewMenu(window: Electron.BrowserWindow, store: Store, reload: () => any): MenuItemConstructorOptions {
|
||||
function viewMenu(window: Electron.BrowserWindow, store: Store, reload: () => void): MenuItemConstructorOptions {
|
||||
return {
|
||||
label: str().view,
|
||||
submenu: [
|
||||
@@ -375,7 +341,7 @@ function viewMenu(window: Electron.BrowserWindow, store: Store, reload: () => an
|
||||
}
|
||||
}
|
||||
|
||||
function menuBarOptions(window: Electron.BrowserWindow, store: Store, reload: () => any) {
|
||||
function menuBarOptions(window: Electron.BrowserWindow, store: Store, reload: () => void) {
|
||||
const useSystemMenuBar = store.get(StoreKeys.UseSystemMenuBar)
|
||||
let isMenuBarVisible = store.get(StoreKeys.MenuBarVisible)
|
||||
window.setMenuBarVisibility(isMenuBarVisible)
|
||||
@@ -406,7 +372,7 @@ function menuBarOptions(window: Electron.BrowserWindow, store: Store, reload: ()
|
||||
]
|
||||
}
|
||||
|
||||
function windowMenu(store: Store, trayManager: TrayManager, reload: () => any): MenuItemConstructorOptions {
|
||||
function windowMenu(store: Store, trayManager: TrayManager, reload: () => void): MenuItemConstructorOptions {
|
||||
return {
|
||||
role: Roles.Window,
|
||||
submenu: [
|
||||
@@ -446,7 +412,7 @@ function macWindowItems(): MenuItemConstructorOptions[] {
|
||||
]
|
||||
}
|
||||
|
||||
function minimizeToTrayItem(store: Store, trayManager: TrayManager, reload: () => any) {
|
||||
function minimizeToTrayItem(store: Store, trayManager: TrayManager, reload: () => void) {
|
||||
const minimizeToTray = trayManager.shouldMinimizeToTray()
|
||||
return {
|
||||
label: str().minimizeToTrayOnClose,
|
||||
|
||||
@@ -48,7 +48,10 @@ class MappingFileHandler {
|
||||
return new MappingFileHandler(mapping, filesManager)
|
||||
}
|
||||
|
||||
constructor(private mapping: MappingFile, private filesManager: FilesManagerInterface) {}
|
||||
constructor(
|
||||
private mapping: MappingFile,
|
||||
private filesManager: FilesManagerInterface,
|
||||
) {}
|
||||
|
||||
get = (componendId: string) => {
|
||||
return this.mapping[componendId]
|
||||
|
||||
@@ -5,6 +5,7 @@ import { StoreData, StoreKeys } from './StoreKeys'
|
||||
import { logError } from './Store'
|
||||
import { FileErrorCodes } from '../File/FileErrorCodes'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function createSanitizedStoreData(data: any = {}): StoreData {
|
||||
return {
|
||||
[StoreKeys.MenuBarVisible]: ensureIsBoolean(data[StoreKeys.MenuBarVisible], true),
|
||||
@@ -27,6 +28,8 @@ export function createSanitizedStoreData(data: any = {}): StoreData {
|
||||
[StoreKeys.LegacyFileBackupsLocation]: data[StoreKeys.LegacyFileBackupsLocation],
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function sanitizeZoomFactor(factor?: any): number {
|
||||
if (typeof factor === 'number' && factor > 0) {
|
||||
return factor
|
||||
@@ -67,7 +70,9 @@ export function parseDataFile(filePath: string) {
|
||||
const fileData = fs.readFileSync(filePath)
|
||||
const userData = JSON.parse(fileData.toString())
|
||||
return createSanitizedStoreData(userData)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Error reading store file', error)
|
||||
if (error.code !== FileErrorCodes.FileDoesNotExist) {
|
||||
logError(error)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"electron-builder": "23.6.0",
|
||||
"electron-notarize": "^1.2.1",
|
||||
"eslint": "*",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-prettier": "^8.9.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
@@ -79,7 +79,7 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "*",
|
||||
"webpack": "*",
|
||||
"webpack-merge": "^5.8.0"
|
||||
"webpack-merge": "*"
|
||||
},
|
||||
"build": {
|
||||
"appId": "org.standardnotes.standardnotes",
|
||||
|
||||
@@ -29,35 +29,35 @@ export const V002Algorithm = Object.freeze({
|
||||
EncryptionIvLength: 128,
|
||||
})
|
||||
|
||||
export enum V003Algorithm {
|
||||
SaltSeedLength = 256,
|
||||
PbkdfCost = 110000,
|
||||
PbkdfOutputLength = 768,
|
||||
EncryptionKeyLength = 256,
|
||||
EncryptionIvLength = 128,
|
||||
}
|
||||
export const V003Algorithm = Object.freeze({
|
||||
SaltSeedLength: 256,
|
||||
PbkdfCost: 110000,
|
||||
PbkdfOutputLength: 768,
|
||||
EncryptionKeyLength: 256,
|
||||
EncryptionIvLength: 128,
|
||||
})
|
||||
|
||||
export enum V004Algorithm {
|
||||
ArgonSaltSeedLength = 256,
|
||||
ArgonSaltLength = 128,
|
||||
ArgonIterations = 5,
|
||||
ArgonMemLimit = 67108864,
|
||||
ArgonOutputKeyBytes = 64,
|
||||
export const V004Algorithm = Object.freeze({
|
||||
ArgonSaltSeedLength: 256,
|
||||
ArgonSaltLength: 128,
|
||||
ArgonIterations: 5,
|
||||
ArgonMemLimit: 67108864,
|
||||
ArgonOutputKeyBytes: 64,
|
||||
|
||||
EncryptionKeyLength = 256,
|
||||
EncryptionNonceLength = 192,
|
||||
EncryptionKeyLength: 256,
|
||||
EncryptionNonceLength: 192,
|
||||
|
||||
AsymmetricEncryptionNonceLength = 192,
|
||||
AsymmetricEncryptionNonceLength: 192,
|
||||
|
||||
MasterKeyEncryptionKeyPairSubKeyNumber = 1,
|
||||
MasterKeyEncryptionKeyPairSubKeyContext = 'sn-pkc-e',
|
||||
MasterKeyEncryptionKeyPairSubKeyBytes = SodiumConstant.crypto_box_SEEDBYTES,
|
||||
MasterKeyEncryptionKeyPairSubKeyNumber: 1,
|
||||
MasterKeyEncryptionKeyPairSubKeyContext: 'sn-pkc-e',
|
||||
MasterKeyEncryptionKeyPairSubKeyBytes: SodiumConstant.crypto_box_SEEDBYTES,
|
||||
|
||||
MasterKeySigningKeyPairSubKeyNumber = 2,
|
||||
MasterKeySigningKeyPairSubKeyContext = 'sn-pkc-s',
|
||||
MasterKeySigningKeyPairSubKeyBytes = SodiumConstant.crypto_sign_SEEDBYTES,
|
||||
MasterKeySigningKeyPairSubKeyNumber: 2,
|
||||
MasterKeySigningKeyPairSubKeyContext: 'sn-pkc-s',
|
||||
MasterKeySigningKeyPairSubKeyBytes: SodiumConstant.crypto_sign_SEEDBYTES,
|
||||
|
||||
PayloadKeyHashingKeySubKeyNumber = 1,
|
||||
PayloadKeyHashingKeySubKeyContext = 'sn-sym-h',
|
||||
PayloadKeyHashingKeySubKeyBytes = SodiumConstant.crypto_generichash_KEYBYTES,
|
||||
}
|
||||
PayloadKeyHashingKeySubKeyNumber: 1,
|
||||
PayloadKeyHashingKeySubKeyContext: 'sn-sym-h',
|
||||
PayloadKeyHashingKeySubKeyBytes: SodiumConstant.crypto_generichash_KEYBYTES,
|
||||
})
|
||||
|
||||
@@ -16,6 +16,6 @@ export function createOperatorForVersion(version: ProtocolVersion, crypto: PureC
|
||||
} else if (version === ProtocolVersion.V004) {
|
||||
return new SNProtocolOperator004(crypto)
|
||||
} else {
|
||||
throw Error(`Unable to find operator for version ${version}`)
|
||||
throw Error(`Unable to find operator for version ${version as string}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
export class StandardException {
|
||||
constructor(public readonly message: string, log = false) {
|
||||
constructor(
|
||||
public readonly message: string,
|
||||
log = false,
|
||||
) {
|
||||
if (log) {
|
||||
console.error('StandardException raised: ', message)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^29.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "4.9.3"
|
||||
"typescript": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { saveFile } from '../utils'
|
||||
export class ClassicFileSaver {
|
||||
public loggingEnabled = false
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private log(...args: any[]): void {
|
||||
if (!this.loggingEnabled) {
|
||||
return
|
||||
|
||||
@@ -8,6 +8,7 @@ export class StreamingFileSaver {
|
||||
|
||||
constructor(private name: string) {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private log(...args: any[]): void {
|
||||
if (!this.loggingEnabled) {
|
||||
return
|
||||
|
||||
@@ -5,8 +5,12 @@ export class ByteChunker {
|
||||
private bytes = new Uint8Array()
|
||||
private index = 1
|
||||
|
||||
constructor(private minimumChunkSize: number, private onChunk: OnChunkCallbackNoProgress) {}
|
||||
constructor(
|
||||
private minimumChunkSize: number,
|
||||
private onChunk: OnChunkCallbackNoProgress,
|
||||
) {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private log(...args: any[]): void {
|
||||
if (!this.loggingEnabled) {
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PureCryptoInterface, StreamDecryptor, SodiumConstant } from '@standardnotes/sncrypto-common'
|
||||
import { PureCryptoInterface, StreamDecryptor, SodiumTag } from '@standardnotes/sncrypto-common'
|
||||
import { FileContent } from '@standardnotes/models'
|
||||
|
||||
export class FileDecryptor {
|
||||
@@ -22,7 +22,7 @@ export class FileDecryptor {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const isFinal = result.tag === SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL
|
||||
const isFinal = result.tag === SodiumTag.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL
|
||||
|
||||
return { decryptedBytes: result.message, isFinalChunk: isFinal }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FileContent } from '@standardnotes/models'
|
||||
import { PureCryptoInterface, StreamEncryptor, SodiumConstant } from '@standardnotes/sncrypto-common'
|
||||
import { PureCryptoInterface, StreamEncryptor, SodiumTag } from '@standardnotes/sncrypto-common'
|
||||
import { FileEncryptor } from './FileEncryptor'
|
||||
|
||||
describe('file encryptor', () => {
|
||||
@@ -46,7 +46,7 @@ describe('file encryptor', () => {
|
||||
expect.any(Object),
|
||||
decryptedBytes,
|
||||
file.remoteIdentifier,
|
||||
SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL,
|
||||
SodiumTag.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL,
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FileContent } from '@standardnotes/models'
|
||||
import { PureCryptoInterface, StreamEncryptor, SodiumConstant } from '@standardnotes/sncrypto-common'
|
||||
import { PureCryptoInterface, StreamEncryptor, SodiumTag } from '@standardnotes/sncrypto-common'
|
||||
|
||||
export class FileEncryptor {
|
||||
private stream!: StreamEncryptor
|
||||
@@ -20,7 +20,7 @@ export class FileEncryptor {
|
||||
throw new Error('FileEncryptor must call initializeHeader first')
|
||||
}
|
||||
|
||||
const tag = isFinalChunk ? SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL : undefined
|
||||
const tag = isFinalChunk ? SodiumTag.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL : undefined
|
||||
|
||||
const encryptedBytes = this.crypto.xchacha20StreamEncryptorPush(
|
||||
this.stream,
|
||||
|
||||
@@ -45,13 +45,13 @@
|
||||
"@typescript-eslint/parser": "*",
|
||||
"babel-jest": "^29.3.1",
|
||||
"detox": "^20.0.3",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint": "*",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"get-yarn-workspaces": "^1.0.2",
|
||||
"metro-react-native-babel-preset": "^0.76.7",
|
||||
"npm-check-updates": "*",
|
||||
"pod-install": "^0.1.38",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier": "*",
|
||||
"prettier-plugin-organize-imports": "^3.2.0",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.3",
|
||||
|
||||
@@ -2,7 +2,10 @@ import { DatabaseItemMetadata, isNotUndefined, TransferPayload } from '@standard
|
||||
import { FlashKeyValueStore } from './FlashKeyValueStore'
|
||||
|
||||
export class DatabaseMetadata {
|
||||
constructor(private identifier: string, private flashStorage: FlashKeyValueStore) {}
|
||||
constructor(
|
||||
private identifier: string,
|
||||
private flashStorage: FlashKeyValueStore,
|
||||
) {}
|
||||
|
||||
runMigration(payloads: TransferPayload[]) {
|
||||
const metadataItems = this.setMetadataForPayloads(payloads)
|
||||
|
||||
@@ -423,7 +423,7 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
failOnCancel: false,
|
||||
})
|
||||
} catch (error) {
|
||||
this.consoleLog(`${error}`)
|
||||
this.consoleLog(error)
|
||||
} finally {
|
||||
if (downloadedTempFilePath) {
|
||||
void this.deleteFileAtPathIfExists(downloadedTempFilePath)
|
||||
@@ -456,7 +456,7 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
await writeFile(path, base64.replace(/data.*base64,/, ''), 'base64')
|
||||
return path
|
||||
} catch (error) {
|
||||
this.consoleLog(`${error}`)
|
||||
this.consoleLog(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ export function FillItemContent<C extends ItemContent = ItemContent>(content: Pa
|
||||
}
|
||||
|
||||
if (!content.appData[DefaultAppDomain][AppDataField.UserModifiedDate]) {
|
||||
content.appData[DefaultAppDomain][AppDataField.UserModifiedDate] = `${new Date()}`
|
||||
content.appData[DefaultAppDomain][AppDataField.UserModifiedDate] = new Date().toString()
|
||||
}
|
||||
|
||||
return content as C
|
||||
|
||||
@@ -7,13 +7,14 @@ import { LegacyAnonymousReference } from './LegacyAnonymousReference'
|
||||
import { LegacyTagToNoteReference } from './LegacyTagToNoteReference'
|
||||
import { Reference } from './Reference'
|
||||
import { TagToParentTagReference } from './TagToParentTagReference'
|
||||
import { AnonymousReference } from './AnonymousReference'
|
||||
|
||||
export const isLegacyAnonymousReference = (x: ContentReference): x is LegacyAnonymousReference => {
|
||||
return (x as any).reference_type === undefined
|
||||
return (x as AnonymousReference).reference_type === undefined
|
||||
}
|
||||
|
||||
export const isReference = (x: ContentReference): x is Reference => {
|
||||
return (x as any).reference_type !== undefined
|
||||
return (x as AnonymousReference).reference_type !== undefined
|
||||
}
|
||||
|
||||
export const isLegacyTagToNoteReference = (
|
||||
|
||||
@@ -24,7 +24,10 @@ export class ItemCounter implements SNIndex {
|
||||
private displayOptions?: AnyDisplayOptions
|
||||
private vaultDisplayOptions?: VaultDisplayOptions
|
||||
|
||||
constructor(private collection: ItemCollection, public observers: TagItemCountChangeObserver[] = []) {}
|
||||
constructor(
|
||||
private collection: ItemCollection,
|
||||
public observers: TagItemCountChangeObserver[] = [],
|
||||
) {}
|
||||
|
||||
public addCountChangeObserver(observer: TagItemCountChangeObserver): () => void {
|
||||
this.observers.push(observer)
|
||||
|
||||
@@ -3,7 +3,10 @@ import { ReadonlyItemCollection } from '../Types'
|
||||
import { CriteriaValidatorInterface } from './CriteriaValidatorInterface'
|
||||
|
||||
export class CollectionCriteriaValidator implements CriteriaValidatorInterface {
|
||||
constructor(private collection: ReadonlyItemCollection, private element: ItemInterface) {}
|
||||
constructor(
|
||||
private collection: ReadonlyItemCollection,
|
||||
private element: ItemInterface,
|
||||
) {}
|
||||
|
||||
public passes(): boolean {
|
||||
return this.collection.has(this.element.uuid)
|
||||
|
||||
@@ -3,7 +3,10 @@ import { DisplayControllerCustomFilter } from '../Types'
|
||||
import { CriteriaValidatorInterface } from './CriteriaValidatorInterface'
|
||||
|
||||
export class CustomFilterCriteriaValidator implements CriteriaValidatorInterface {
|
||||
constructor(private customFilter: DisplayControllerCustomFilter, private element: DecryptedItemInterface) {}
|
||||
constructor(
|
||||
private customFilter: DisplayControllerCustomFilter,
|
||||
private element: DecryptedItemInterface,
|
||||
) {}
|
||||
|
||||
public passes(): boolean {
|
||||
return this.customFilter(this.element)
|
||||
|
||||
@@ -3,7 +3,10 @@ import { DecryptedItemInterface } from '../../../Abstract/Item'
|
||||
import { KeySystemIdentifier } from '../../../Syncable/KeySystemRootKey/KeySystemIdentifier'
|
||||
|
||||
export class ExcludeVaultsCriteriaValidator implements CriteriaValidatorInterface {
|
||||
constructor(private excludeVaults: KeySystemIdentifier[], private element: DecryptedItemInterface) {}
|
||||
constructor(
|
||||
private excludeVaults: KeySystemIdentifier[],
|
||||
private element: DecryptedItemInterface,
|
||||
) {}
|
||||
|
||||
public passes(): boolean {
|
||||
const doesElementBelongToExcludedVault = this.excludeVaults.some(
|
||||
|
||||
@@ -3,7 +3,10 @@ import { DecryptedItemInterface } from '../../../Abstract/Item'
|
||||
import { KeySystemIdentifier } from '../../../Syncable/KeySystemRootKey/KeySystemIdentifier'
|
||||
|
||||
export class ExclusiveVaultCriteriaValidator implements CriteriaValidatorInterface {
|
||||
constructor(private exclusiveVault: KeySystemIdentifier, private element: DecryptedItemInterface) {}
|
||||
constructor(
|
||||
private exclusiveVault: KeySystemIdentifier,
|
||||
private element: DecryptedItemInterface,
|
||||
) {}
|
||||
|
||||
public passes(): boolean {
|
||||
return this.element.key_system_identifier === this.exclusiveVault
|
||||
|
||||
@@ -2,7 +2,10 @@ import { DecryptedItemInterface } from './../../../Abstract/Item/Interfaces/Decr
|
||||
import { CriteriaValidatorInterface } from './CriteriaValidatorInterface'
|
||||
|
||||
export class HiddenContentCriteriaValidator implements CriteriaValidatorInterface {
|
||||
constructor(private hiddenContentTypes: string[], private element: DecryptedItemInterface) {}
|
||||
constructor(
|
||||
private hiddenContentTypes: string[],
|
||||
private element: DecryptedItemInterface,
|
||||
) {}
|
||||
|
||||
public passes(): boolean {
|
||||
return !this.hiddenContentTypes.includes(this.element.content_type)
|
||||
|
||||
@@ -81,7 +81,7 @@ export function predicateFromDSLString<T extends PredicateTarget>(dsl: string):
|
||||
const predicateJson = predicateDSLArrayToJsonPredicate(components as RawPredicateInArrayForm)
|
||||
return predicateFromJson(predicateJson)
|
||||
} catch (e) {
|
||||
throw Error(`Invalid smart view syntax ${e}`)
|
||||
throw Error(`Invalid smart view syntax ${JSON.stringify(e)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { PredicateTarget, PredicateInterface, PredicateJsonForm, StringKey } from './Interface'
|
||||
|
||||
export class IncludesPredicate<T extends PredicateTarget> implements PredicateInterface<T> {
|
||||
constructor(private readonly keypath: StringKey<T>, public readonly predicate: PredicateInterface<T>) {}
|
||||
constructor(
|
||||
private readonly keypath: StringKey<T>,
|
||||
public readonly predicate: PredicateInterface<T>,
|
||||
) {}
|
||||
|
||||
matchesItem(item: T): boolean {
|
||||
const keyPathComponents = this.keypath.split('.') as StringKey<T>[]
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface PredicateJsonForm {
|
||||
}
|
||||
|
||||
export const AllPredicateCompoundOperators = ['and', 'or'] as const
|
||||
export type PredicateCompoundOperator = typeof AllPredicateCompoundOperators[number]
|
||||
export type PredicateCompoundOperator = (typeof AllPredicateCompoundOperators)[number]
|
||||
|
||||
export const AllNonCompoundPredicateOperators = [
|
||||
'!=',
|
||||
@@ -31,7 +31,7 @@ export const AllNonCompoundPredicateOperators = [
|
||||
|
||||
export const AllPredicateOperators = [...AllPredicateCompoundOperators, ...AllNonCompoundPredicateOperators] as const
|
||||
|
||||
export type PredicateOperator = typeof AllPredicateOperators[number]
|
||||
export type PredicateOperator = (typeof AllPredicateOperators)[number]
|
||||
|
||||
export type SureValue = number | number[] | string[] | string | Date | boolean | false | ''
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { HttpErrorResponse, getErrorFromErrorResponse } from '../Http'
|
||||
|
||||
export class ClientDisplayableError {
|
||||
constructor(public text: string, public title?: string, public tag?: string) {
|
||||
constructor(
|
||||
public text: string,
|
||||
public title?: string,
|
||||
public tag?: string,
|
||||
) {
|
||||
console.error('Client Displayable Error:', text, title || '', tag || '')
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"@types/node": "^20.2.5",
|
||||
"@typescript-eslint/eslint-plugin": "*",
|
||||
"@typescript-eslint/parser": "*",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint": "*",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^29.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
|
||||
@@ -3,7 +3,10 @@ import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||
import { TrustedContactInterface, TrustedContactMutator } from '@standardnotes/models'
|
||||
|
||||
export class EditContact {
|
||||
constructor(private mutator: MutatorClientInterface, private sync: SyncServiceInterface) {}
|
||||
constructor(
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
contact: TrustedContactInterface,
|
||||
|
||||
@@ -4,7 +4,10 @@ import { ReuploadAllInvites } from '../../VaultInvite/UseCase/ReuploadAllInvites
|
||||
import { ResendAllMessages } from '../../AsymmetricMessage/UseCase/ResendAllMessages'
|
||||
|
||||
export class HandleKeyPairChange implements UseCaseInterface<void> {
|
||||
constructor(private reuploadAllInvites: ReuploadAllInvites, private resendAllMessages: ResendAllMessages) {}
|
||||
constructor(
|
||||
private reuploadAllInvites: ReuploadAllInvites,
|
||||
private resendAllMessages: ResendAllMessages,
|
||||
) {}
|
||||
|
||||
async execute(dto: {
|
||||
newKeys: {
|
||||
|
||||
@@ -10,7 +10,10 @@ import { EncryptMessage } from '../../Encryption/UseCase/Asymmetric/EncryptMessa
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class SendOwnContactChangeMessage implements UseCaseInterface<AsymmetricMessageServerHash> {
|
||||
constructor(private encryptMessage: EncryptMessage, private sendMessage: SendMessage) {}
|
||||
constructor(
|
||||
private encryptMessage: EncryptMessage,
|
||||
private sendMessage: SendMessage,
|
||||
) {}
|
||||
|
||||
async execute(params: {
|
||||
senderOldKeyPair: PkcKeyPair
|
||||
|
||||
@@ -7,7 +7,10 @@ import { ContentTypesUsingRootKeyEncryption } from '@standardnotes/models'
|
||||
* When the user root key changes, we must re-encrypt all relevant items with this new root key (by simply re-syncing).
|
||||
*/
|
||||
export class ReencryptTypeAItems implements UseCaseInterface<void> {
|
||||
constructor(private items: ItemManagerInterface, private mutator: MutatorClientInterface) {}
|
||||
constructor(
|
||||
private items: ItemManagerInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
) {}
|
||||
|
||||
public async execute(): Promise<Result<void>> {
|
||||
const items = this.items.getItems(ContentTypesUsingRootKeyEncryption())
|
||||
|
||||
@@ -31,7 +31,7 @@ export class IntegrityService
|
||||
|
||||
const integrityCheckResponse = await this.integrityApi.checkIntegrity(this.payloadManager.integrityPayloads)
|
||||
if (isErrorResponse(integrityCheckResponse)) {
|
||||
this.log(`Could not obtain integrity check: ${integrityCheckResponse.data.error}`)
|
||||
this.log(`Could not obtain integrity check: ${integrityCheckResponse.data.error?.message}`)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export class IntegrityService
|
||||
) {
|
||||
this.log(
|
||||
`Could not obtain item for integrity adjustments: ${
|
||||
isErrorResponse(serverItemResponse) ? serverItemResponse.data.error : ''
|
||||
isErrorResponse(serverItemResponse) ? serverItemResponse.data.error?.message : ''
|
||||
}`,
|
||||
)
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
|
||||
case KeyMode.RootKeyPlusWrapper:
|
||||
return true
|
||||
default:
|
||||
throw Error(`Unhandled keyMode value '${this.keyMode}'.`)
|
||||
throw Error('Unhandled keyMode value.')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
|
||||
/** Root key is simply changing, mode stays the same */
|
||||
/** this.keyMode = this.keyMode; */
|
||||
} else {
|
||||
throw Error(`Unhandled key mode for setNewRootKey ${this.keyMode}`)
|
||||
throw Error('Unhandled key mode for setNewRootKey')
|
||||
}
|
||||
|
||||
this.setRootKeyInstance(key)
|
||||
@@ -396,7 +396,7 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
|
||||
} else if (this.keyMode === KeyMode.RootKeyNone) {
|
||||
return undefined
|
||||
} else {
|
||||
throw `Unhandled key mode for getRootKeyParams ${this.keyMode}`
|
||||
throw 'Unhandled key mode for getRootKeyParams'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export class ConvertToSharedVault {
|
||||
|
||||
const serverResult = await this.sharedVaultServer.createSharedVault()
|
||||
if (isErrorResponse(serverResult)) {
|
||||
return ClientDisplayableError.FromString(`Failed to create shared vault ${serverResult}`)
|
||||
return ClientDisplayableError.FromString(`Failed to create shared vault ${JSON.stringify(serverResult)}`)
|
||||
}
|
||||
|
||||
const serverVaultHash = serverResult.data.sharedVault
|
||||
|
||||
@@ -17,7 +17,7 @@ export class DeleteSharedVault {
|
||||
})
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromString(`Failed to delete vault ${response}`)
|
||||
return ClientDisplayableError.FromString(`Failed to delete vault ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
await this.deleteVault.execute(params.sharedVault)
|
||||
|
||||
@@ -4,7 +4,10 @@ import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||
import { GetSharedVaults } from './GetSharedVaults'
|
||||
|
||||
export class GetOwnedSharedVaults implements SyncUseCaseInterface<SharedVaultListingInterface[]> {
|
||||
constructor(private getSharedVaults: GetSharedVaults, private isVaultOwnwer: IsVaultOwner) {}
|
||||
constructor(
|
||||
private getSharedVaults: GetSharedVaults,
|
||||
private isVaultOwnwer: IsVaultOwner,
|
||||
) {}
|
||||
|
||||
execute(dto: { userUuid: string }): Result<SharedVaultListingInterface[]> {
|
||||
const sharedVaults = this.getSharedVaults.execute().getValue()
|
||||
|
||||
@@ -99,7 +99,7 @@ export class NotifyVaultUsersOfKeyRotation implements UseCaseInterface<void> {
|
||||
})
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(`Failed to delete existing invites ${response}`)
|
||||
return Result.fail(`Failed to delete existing invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
@@ -109,7 +109,7 @@ export class NotifyVaultUsersOfKeyRotation implements UseCaseInterface<void> {
|
||||
const response = await this.inviteServer.getOutboundUserInvites()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(`Failed to get outbound user invites ${response}`)
|
||||
return Result.fail(`Failed to get outbound user invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
const invites = response.data.invites
|
||||
|
||||
@@ -4,7 +4,10 @@ import { AnyItemInterface } from '@standardnotes/models'
|
||||
import { Uuids } from '@standardnotes/utils'
|
||||
|
||||
export class DiscardItemsLocally {
|
||||
constructor(private readonly items: ItemManagerInterface, private readonly storage: StorageServiceInterface) {}
|
||||
constructor(
|
||||
private readonly items: ItemManagerInterface,
|
||||
private readonly storage: StorageServiceInterface,
|
||||
) {}
|
||||
|
||||
async execute(items: AnyItemInterface[]): Promise<void> {
|
||||
this.items.removeItemsFromMemory(items)
|
||||
|
||||
@@ -66,7 +66,7 @@ export class ReuploadAllInvites implements UseCaseInterface<void> {
|
||||
const response = await this.inviteServer.getOutboundUserInvites()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(`Failed to get outbound user invites ${response}`)
|
||||
return Result.fail(`Failed to get outbound user invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
const invites = response.data.invites
|
||||
@@ -78,7 +78,7 @@ export class ReuploadAllInvites implements UseCaseInterface<void> {
|
||||
const response = await this.inviteServer.deleteAllOutboundInvites()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(`Failed to delete existing invites ${response}`)
|
||||
return Result.fail(`Failed to delete existing invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
|
||||
@@ -64,7 +64,7 @@ export class ReuploadVaultInvites implements UseCaseInterface<void> {
|
||||
const response = await this.inviteServer.getOutboundUserInvites()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(`Failed to get outbound user invites ${response}`)
|
||||
return Result.fail(`Failed to get outbound user invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
const invites = response.data.invites
|
||||
@@ -78,7 +78,7 @@ export class ReuploadVaultInvites implements UseCaseInterface<void> {
|
||||
})
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return Result.fail(`Failed to delete existing invites ${response}`)
|
||||
return Result.fail(`Failed to delete existing invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
|
||||
@@ -109,7 +109,7 @@ export class VaultInviteService
|
||||
const response = await this.invitesServer.getInboundUserInvites()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromString(`Failed to get inbound user invites ${response}`)
|
||||
return ClientDisplayableError.FromString(`Failed to get inbound user invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
this.pendingInvites = {}
|
||||
@@ -125,7 +125,7 @@ export class VaultInviteService
|
||||
const response = await this.invitesServer.getOutboundUserInvites()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromString(`Failed to get outbound user invites ${response}`)
|
||||
return ClientDisplayableError.FromString(`Failed to get outbound user invites ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
if (sharedVault) {
|
||||
@@ -220,7 +220,7 @@ export class VaultInviteService
|
||||
})
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromString(`Failed to delete invite ${response}`)
|
||||
return ClientDisplayableError.FromString(`Failed to delete invite ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
delete this.pendingInvites[invite.uuid]
|
||||
|
||||
@@ -5,7 +5,10 @@ import { FindContact } from '../../Contacts/UseCase/FindContact'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class GetVaultContacts implements UseCaseInterface<TrustedContactInterface[]> {
|
||||
constructor(private findContact: FindContact, private getVaultUsers: GetVaultUsers) {}
|
||||
constructor(
|
||||
private findContact: FindContact,
|
||||
private getVaultUsers: GetVaultUsers,
|
||||
) {}
|
||||
|
||||
async execute(dto: { sharedVaultUuid: string; readFromCache: boolean }): Promise<Result<TrustedContactInterface[]>> {
|
||||
const users = await this.getVaultUsers.execute({
|
||||
|
||||
@@ -4,7 +4,10 @@ import { SharedVaultUsersServerInterface } from '@standardnotes/api'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class GetVaultUsers implements UseCaseInterface<SharedVaultUserServerHash[]> {
|
||||
constructor(private vaultUsersServer: SharedVaultUsersServerInterface, private cache: VaultUserCache) {}
|
||||
constructor(
|
||||
private vaultUsersServer: SharedVaultUsersServerInterface,
|
||||
private cache: VaultUserCache,
|
||||
) {}
|
||||
|
||||
async execute(params: {
|
||||
sharedVaultUuid: string
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "*",
|
||||
"@typescript-eslint/parser": "*",
|
||||
"eslint": "*",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"typescript": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PkcKeyPair } from '../Types'
|
||||
import { PkcKeyPair, SodiumTag } from '../Types'
|
||||
import { Base64String } from '../Types/Base64String'
|
||||
import { Base64URLSafeString } from '../Types/Base64URLSafeString'
|
||||
import { HexString } from '../Types/HexString'
|
||||
import { SodiumConstant } from '../Types/SodiumConstant'
|
||||
import { StreamDecryptor } from '../Types/StreamDecryptor'
|
||||
import { StreamEncryptor } from '../Types/StreamEncryptor'
|
||||
import { Utf8String } from '../Types/Utf8String'
|
||||
@@ -122,7 +121,7 @@ export interface PureCryptoInterface {
|
||||
encryptor: StreamEncryptor,
|
||||
plainBuffer: Uint8Array,
|
||||
assocData: Utf8String,
|
||||
tag?: SodiumConstant,
|
||||
tag?: SodiumTag,
|
||||
): Uint8Array
|
||||
|
||||
xchacha20StreamInitDecryptor(header: Base64String, key: HexString): StreamDecryptor
|
||||
@@ -131,7 +130,7 @@ export interface PureCryptoInterface {
|
||||
decryptor: StreamDecryptor,
|
||||
encryptedBuffer: Uint8Array,
|
||||
assocData: Utf8String,
|
||||
): { message: Uint8Array; tag: SodiumConstant } | false
|
||||
): { message: Uint8Array; tag: SodiumTag } | false
|
||||
|
||||
sodiumCryptoBoxEasyEncrypt(
|
||||
message: Utf8String,
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
export enum SodiumConstant {
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_STATEBYTES = 52,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80,
|
||||
crypto_box_SEEDBYTES = 32,
|
||||
crypto_sign_SEEDBYTES = 32,
|
||||
crypto_generichash_KEYBYTES = 32,
|
||||
export const SodiumConstant = {
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_STATEBYTES: 52,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES: 17,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES: 24,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES: 32,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX: 0x3fffffff80,
|
||||
crypto_box_SEEDBYTES: 32,
|
||||
crypto_sign_SEEDBYTES: 32,
|
||||
crypto_generichash_KEYBYTES: 32,
|
||||
}
|
||||
|
||||
6
packages/sncrypto-common/src/Types/SodiumTag.ts
Normal file
6
packages/sncrypto-common/src/Types/SodiumTag.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum SodiumTag {
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2,
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3,
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SodiumConstant } from './SodiumConstant'
|
||||
import { SodiumTag } from './SodiumTag'
|
||||
|
||||
export type StreamDecryptorResult = {
|
||||
message: Uint8Array
|
||||
tag: SodiumConstant
|
||||
tag: SodiumTag
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
export * from './Base64String'
|
||||
export * from './Base64URLSafeString'
|
||||
export * from './HexString'
|
||||
export * from './PkcKeyPair'
|
||||
export * from './SodiumConstant'
|
||||
export * from './SodiumStateAddress'
|
||||
export * from './SodiumTag'
|
||||
export * from './StreamDecryptor'
|
||||
export * from './StreamDecryptorResult'
|
||||
export * from './StreamEncryptor'
|
||||
export * from './Unencrypted'
|
||||
export * from './Utf8String'
|
||||
export * from './PkcKeyPair'
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
StreamEncryptor,
|
||||
StreamDecryptor,
|
||||
SodiumConstant,
|
||||
SodiumTag,
|
||||
StreamDecryptorResult,
|
||||
Base64String,
|
||||
Base64URLSafeString,
|
||||
@@ -299,7 +300,7 @@ export class SNWebCrypto implements PureCryptoInterface {
|
||||
encryptor: StreamEncryptor,
|
||||
plainBuffer: Uint8Array,
|
||||
assocData?: Utf8String,
|
||||
tag: SodiumConstant = SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH,
|
||||
tag: SodiumTag = SodiumTag.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH,
|
||||
): Uint8Array {
|
||||
const encryptedBuffer = sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
encryptor.state as sodium.StateAddress,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './crypto'
|
||||
export * from './utils'
|
||||
export { SodiumConstant } from '@standardnotes/sncrypto-common'
|
||||
export { SodiumConstant, SodiumTag } from '@standardnotes/sncrypto-common'
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import { ApplicationEvent, SyncEvent } from '@standardnotes/services'
|
||||
export { SyncEvent }
|
||||
|
||||
export function applicationEventForSyncEvent(syncEvent: SyncEvent) {
|
||||
return (
|
||||
{
|
||||
[SyncEvent.SyncCompletedWithAllItemsUploaded]: ApplicationEvent.CompletedFullSync,
|
||||
[SyncEvent.PaginatedSyncRequestCompleted]: ApplicationEvent.CompletedIncrementalSync,
|
||||
[SyncEvent.SyncError]: ApplicationEvent.FailedSync,
|
||||
[SyncEvent.SyncTakingTooLong]: ApplicationEvent.HighLatencySync,
|
||||
[SyncEvent.EnterOutOfSync]: ApplicationEvent.EnteredOutOfSync,
|
||||
[SyncEvent.ExitOutOfSync]: ApplicationEvent.ExitedOutOfSync,
|
||||
[SyncEvent.LocalDataLoaded]: ApplicationEvent.LocalDataLoaded,
|
||||
[SyncEvent.MajorDataChange]: ApplicationEvent.MajorDataChange,
|
||||
[SyncEvent.LocalDataIncrementalLoad]: ApplicationEvent.LocalDataIncrementalLoad,
|
||||
[SyncEvent.StatusChanged]: ApplicationEvent.SyncStatusChanged,
|
||||
[SyncEvent.SyncDidBeginProcessing]: ApplicationEvent.WillSync,
|
||||
[SyncEvent.InvalidSession]: ApplicationEvent.InvalidSyncSession,
|
||||
[SyncEvent.DatabaseReadError]: ApplicationEvent.LocalDatabaseReadError,
|
||||
[SyncEvent.DatabaseWriteError]: ApplicationEvent.LocalDatabaseWriteError,
|
||||
[SyncEvent.DownloadFirstSyncCompleted]: ApplicationEvent.CompletedInitialSync,
|
||||
} as any
|
||||
)[syncEvent]
|
||||
const map: Record<string, ApplicationEvent> = {
|
||||
[SyncEvent.SyncCompletedWithAllItemsUploaded]: ApplicationEvent.CompletedFullSync,
|
||||
[SyncEvent.PaginatedSyncRequestCompleted]: ApplicationEvent.CompletedIncrementalSync,
|
||||
[SyncEvent.SyncError]: ApplicationEvent.FailedSync,
|
||||
[SyncEvent.SyncTakingTooLong]: ApplicationEvent.HighLatencySync,
|
||||
[SyncEvent.EnterOutOfSync]: ApplicationEvent.EnteredOutOfSync,
|
||||
[SyncEvent.ExitOutOfSync]: ApplicationEvent.ExitedOutOfSync,
|
||||
[SyncEvent.LocalDataLoaded]: ApplicationEvent.LocalDataLoaded,
|
||||
[SyncEvent.MajorDataChange]: ApplicationEvent.MajorDataChange,
|
||||
[SyncEvent.LocalDataIncrementalLoad]: ApplicationEvent.LocalDataIncrementalLoad,
|
||||
[SyncEvent.StatusChanged]: ApplicationEvent.SyncStatusChanged,
|
||||
[SyncEvent.SyncDidBeginProcessing]: ApplicationEvent.WillSync,
|
||||
[SyncEvent.InvalidSession]: ApplicationEvent.InvalidSyncSession,
|
||||
[SyncEvent.DatabaseReadError]: ApplicationEvent.LocalDatabaseReadError,
|
||||
[SyncEvent.DatabaseWriteError]: ApplicationEvent.LocalDatabaseWriteError,
|
||||
[SyncEvent.DownloadFirstSyncCompleted]: ApplicationEvent.CompletedInitialSync,
|
||||
}
|
||||
|
||||
export function applicationEventForSyncEvent(syncEvent: SyncEvent): ApplicationEvent | undefined {
|
||||
return map[syncEvent]
|
||||
}
|
||||
|
||||
@@ -26,7 +26,10 @@ export class SNApplicationGroup<D extends DeviceInterface = DeviceInterface> ext
|
||||
private descriptorRecord!: DescriptorRecord
|
||||
callback!: AppGroupCallback<D>
|
||||
|
||||
constructor(public device: D, internalEventBus?: InternalEventBusInterface) {
|
||||
constructor(
|
||||
public device: D,
|
||||
internalEventBus?: InternalEventBusInterface,
|
||||
) {
|
||||
if (internalEventBus === undefined) {
|
||||
internalEventBus = new InternalEventBus()
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ import { SettingName } from '@standardnotes/settings'
|
||||
import { SettingsClientInterface } from '@Lib/Services/Settings/SettingsClientInterface'
|
||||
|
||||
export class GetRecoveryCodes implements UseCaseInterface<string> {
|
||||
constructor(private authClient: AuthClientInterface, private settingsClient: SettingsClientInterface) {}
|
||||
constructor(
|
||||
private authClient: AuthClientInterface,
|
||||
private settingsClient: SettingsClientInterface,
|
||||
) {}
|
||||
|
||||
async execute(): Promise<Result<string>> {
|
||||
const existingRecoveryCodes = await this.settingsClient.getSetting(
|
||||
|
||||
@@ -4,7 +4,10 @@ import { ComponentInterface, PrefKey, SNTag } from '@standardnotes/models'
|
||||
import { ItemManagerInterface, PreferenceServiceInterface } from '@standardnotes/services'
|
||||
|
||||
export class GetDefaultEditorIdentifier implements SyncUseCaseInterface<string> {
|
||||
constructor(private preferences: PreferenceServiceInterface, private items: ItemManagerInterface) {}
|
||||
constructor(
|
||||
private preferences: PreferenceServiceInterface,
|
||||
private items: ItemManagerInterface,
|
||||
) {}
|
||||
|
||||
execute(currentTag?: SNTag): Result<string> {
|
||||
if (currentTag) {
|
||||
|
||||
@@ -250,7 +250,7 @@ export class FeaturesService
|
||||
|
||||
return this.downloadOfflineRoles(offlineRepo)
|
||||
} catch (err) {
|
||||
return new ClientDisplayableError(`${API_MESSAGE_FAILED_OFFLINE_ACTIVATION}, ${err}`)
|
||||
return new ClientDisplayableError(`${API_MESSAGE_FAILED_OFFLINE_ACTIVATION}, ${JSON.stringify(err)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import { MutatorClientInterface } from '@standardnotes/services'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
|
||||
export class MigrateFeatureRepoToUserSettingUseCase {
|
||||
constructor(private mutator: MutatorClientInterface, private settings: SettingsClientInterface) {}
|
||||
constructor(
|
||||
private mutator: MutatorClientInterface,
|
||||
private settings: SettingsClientInterface,
|
||||
) {}
|
||||
|
||||
async execute(featureRepos: SNFeatureRepo[] = []): Promise<void> {
|
||||
for (const item of featureRepos) {
|
||||
|
||||
@@ -641,7 +641,7 @@ export class SyncService
|
||||
} else if (useStrategy === SyncQueueStrategy.ForceSpawnNew) {
|
||||
return this.queueStrategyForceSpawnNew(options)
|
||||
} else {
|
||||
throw Error(`Unhandled timing strategy ${useStrategy}`)
|
||||
throw Error('Unhandled timing strategy')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,6 @@
|
||||
"uuid": "^9.0.0",
|
||||
"webpack": "*",
|
||||
"webpack-cli": "*",
|
||||
"webpack-merge": "^5.8.0"
|
||||
"webpack-merge": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export class ArchiveManager {
|
||||
}
|
||||
|
||||
formattedDateForExports() {
|
||||
const string = `${new Date()}`
|
||||
const string = new Date().toString()
|
||||
// Match up to the first parenthesis, i.e do not include '(Central Standard Time)'
|
||||
const matches = string.match(/^(.*?) \(/)
|
||||
if (matches && matches.length >= 2) {
|
||||
|
||||
@@ -12,7 +12,10 @@ export class ChangelogService implements ChangelogServiceInterface {
|
||||
private changeLog?: Changelog
|
||||
private lastReadChangeListeners: ChangelogLastReadVersionListener[] = []
|
||||
|
||||
constructor(private environment: Environment, private diskService: StorageServiceInterface) {}
|
||||
constructor(
|
||||
private environment: Environment,
|
||||
private diskService: StorageServiceInterface,
|
||||
) {}
|
||||
|
||||
public addLastReadChangeListener(listener: ChangelogLastReadVersionListener) {
|
||||
this.lastReadChangeListeners.push(listener)
|
||||
|
||||
@@ -12,7 +12,10 @@ export class KeyboardService {
|
||||
private commandHandlers = new Set<KeyboardCommandHandler>()
|
||||
private commandMap = new Map<KeyboardCommand, KeyboardShortcut>()
|
||||
|
||||
constructor(private platform: Platform, environment: Environment) {
|
||||
constructor(
|
||||
private platform: Platform,
|
||||
environment: Environment,
|
||||
) {
|
||||
window.addEventListener('keydown', this.handleKeyDown)
|
||||
window.addEventListener('keyup', this.handleKeyUp)
|
||||
window.addEventListener('blur', this.handleWindowBlur)
|
||||
|
||||
@@ -14,4 +14,4 @@ const PREFERENCE_IDS = [
|
||||
'whats-new',
|
||||
] as const
|
||||
|
||||
export type PreferenceId = typeof PREFERENCE_IDS[number]
|
||||
export type PreferenceId = (typeof PREFERENCE_IDS)[number]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const ValidAppViewRoutes = ['u2f', 'extension'] as const
|
||||
|
||||
export type AppViewRouteParam = typeof ValidAppViewRoutes[number]
|
||||
export type AppViewRouteParam = (typeof ValidAppViewRoutes)[number]
|
||||
|
||||
@@ -6,7 +6,10 @@ import { Uuid } from '@standardnotes/domain-core'
|
||||
export class ActiveThemeList {
|
||||
private list: (NativeFeatureIdentifier | Uuid)[] = []
|
||||
|
||||
constructor(private items: ItemManagerInterface, initialList?: (NativeFeatureIdentifier | Uuid)[]) {
|
||||
constructor(
|
||||
private items: ItemManagerInterface,
|
||||
initialList?: (NativeFeatureIdentifier | Uuid)[],
|
||||
) {
|
||||
if (initialList) {
|
||||
this.list = initialList
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
export const classNames = (...values: any[]): string => {
|
||||
return values.map((value) => (typeof value === 'string' ? value : null)).join(' ')
|
||||
import { isNotUndefined } from './Utils'
|
||||
|
||||
export const classNames = (...values: (string | null | undefined | boolean)[]): string => {
|
||||
return values
|
||||
.map((value) => (typeof value === 'string' ? value : null))
|
||||
.filter(isNotUndefined)
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
"dayjs": "^1.11.7",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "*",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint-config-prettier": "^8.9.0",
|
||||
"eslint-plugin-react": "^7.33.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"html-webpack-plugin": "^5.5.3",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
@@ -87,7 +87,7 @@
|
||||
"postcss": "^8.4.19",
|
||||
"postcss-loader": "^7.0.2",
|
||||
"prettier": "*",
|
||||
"prettier-plugin-tailwindcss": "^0.4.0",
|
||||
"prettier-plugin-tailwindcss": "^0.4.1",
|
||||
"qrcode.react": "^3.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -101,7 +101,7 @@
|
||||
"webextension-polyfill": "^0.10.0",
|
||||
"webpack": "*",
|
||||
"webpack-dev-server": "*",
|
||||
"webpack-merge": "^5.8.0"
|
||||
"webpack-merge": "*"
|
||||
},
|
||||
"lint-staged": {
|
||||
"app/**/*.{js,ts,jsx,tsx}": "eslint --cache --fix",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
printWidth: 120,
|
||||
semi: false,
|
||||
plugins: [require('prettier-plugin-tailwindcss')],
|
||||
}
|
||||
7
packages/web/prettier.json
Normal file
7
packages/web/prettier.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 120,
|
||||
"semi": false,
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
@@ -20,7 +20,10 @@ export class Database {
|
||||
private locked = true
|
||||
private db?: IDBDatabase
|
||||
|
||||
constructor(public databaseName: string, private alertService?: AlertService) {}
|
||||
constructor(
|
||||
public databaseName: string,
|
||||
private alertService?: AlertService,
|
||||
) {}
|
||||
|
||||
public deinit(): void {
|
||||
;(this.alertService as unknown) = undefined
|
||||
|
||||
@@ -24,7 +24,11 @@ const createApplication = (
|
||||
}
|
||||
|
||||
export class WebApplicationGroup extends SNApplicationGroup<WebOrDesktopDevice> {
|
||||
constructor(private defaultSyncServerHost: string, device: WebOrDesktopDevice, private webSocketUrl: string) {
|
||||
constructor(
|
||||
private defaultSyncServerHost: string,
|
||||
device: WebOrDesktopDevice,
|
||||
private webSocketUrl: string,
|
||||
) {
|
||||
super(device)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,17 @@ import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
|
||||
import { autorun, IReactionDisposer, IReactionPublic } from 'mobx'
|
||||
import { Component } from 'react'
|
||||
|
||||
export type PureComponentState = Partial<Record<string, any>>
|
||||
export type PureComponentProps = Partial<Record<string, any>>
|
||||
export type PureComponentState = Partial<Record<string, unknown>>
|
||||
export type PureComponentProps = Partial<Record<string, unknown>>
|
||||
|
||||
export abstract class AbstractComponent<P = PureComponentProps, S = PureComponentState> extends Component<P, S> {
|
||||
private unsubApp!: () => void
|
||||
private reactionDisposers: IReactionDisposer[] = []
|
||||
|
||||
constructor(props: P, protected application: WebApplication) {
|
||||
constructor(
|
||||
props: P,
|
||||
protected application: WebApplication,
|
||||
) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ const ContentListHeader = ({
|
||||
<div className="flex">
|
||||
<div className="relative" ref={displayOptionsContainerRef}>
|
||||
<RoundIconButton
|
||||
className={classNames(showDisplayOptionsMenu && 'bg-contrast')}
|
||||
className={classNames(showDisplayOptionsMenu ? 'bg-contrast' : undefined)}
|
||||
onClick={toggleDisplayOptionsMenu}
|
||||
ref={displayOptionsButtonRef}
|
||||
icon="sort-descending"
|
||||
|
||||
@@ -136,9 +136,9 @@ export const InfinteScroller = forwardRef<InfiniteScrollerInterface, Props>(
|
||||
|
||||
const _paginateFront = useCallback(() => {
|
||||
if (direction === 'vertical') {
|
||||
setScrollSize(scrollArea!.current!.scrollHeight)
|
||||
setScrollSize(scrollArea.current!.scrollHeight)
|
||||
} else {
|
||||
setScrollSize(scrollArea!.current!.scrollWidth)
|
||||
setScrollSize(scrollArea.current!.scrollWidth)
|
||||
}
|
||||
setDidPaginateFront(true)
|
||||
paginateFront()
|
||||
|
||||
@@ -77,6 +77,7 @@ class Footer extends AbstractComponent<Props, State> {
|
||||
this.onNewUpdateAvailable()
|
||||
break
|
||||
case WebAppEvent.EditorFocused:
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if ((data as any).eventSource === EditorEventSource.UserInteraction) {
|
||||
this.closeAccountMenu()
|
||||
}
|
||||
@@ -87,6 +88,7 @@ class Footer extends AbstractComponent<Props, State> {
|
||||
case WebAppEvent.EndedBackupDownload: {
|
||||
const successMessage = 'Successfully saved backup.'
|
||||
const errorMessage = 'Unable to save local backup.'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
statusService.setMessage((data as any).success ? successMessage : errorMessage)
|
||||
|
||||
const twoSeconds = 2000
|
||||
|
||||
@@ -28,7 +28,7 @@ const IconPicker = ({ selectedValue, onIconChange, platform, className, useIconG
|
||||
label: value,
|
||||
value: value,
|
||||
icon: value,
|
||||
} as DropdownItem),
|
||||
}) as DropdownItem,
|
||||
),
|
||||
[iconKeys],
|
||||
)
|
||||
|
||||
@@ -99,7 +99,7 @@ const ImportModalFileItem = ({
|
||||
{file.status === 'pending' && 'Could not auto-detect service. Please select manually.'}
|
||||
{file.status === 'parsing' && 'Parsing...'}
|
||||
{file.status === 'importing' && 'Importing...'}
|
||||
{file.status === 'error' && `${file.error}`}
|
||||
{file.status === 'error' && JSON.stringify(file.error)}
|
||||
{file.status === 'success' && file.successMessage}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,10 @@ export class FileViewController implements ItemViewControllerInterface {
|
||||
private removeStreamObserver?: () => void
|
||||
public runtimeId = `${Math.random()}`
|
||||
|
||||
constructor(private application: SNApplication, public item: FileItem) {}
|
||||
constructor(
|
||||
private application: SNApplication,
|
||||
public item: FileItem,
|
||||
) {}
|
||||
|
||||
deinit() {
|
||||
this.dealloced = true
|
||||
|
||||
@@ -18,7 +18,10 @@ export class PreferencesSessionController {
|
||||
private _menu: PreferencesMenuItem[]
|
||||
private _extensionLatestVersions: PackageProvider = new PackageProvider(new Map())
|
||||
|
||||
constructor(private application: WebApplication, private readonly _enableUnfinishedFeatures: boolean) {
|
||||
constructor(
|
||||
private application: WebApplication,
|
||||
private readonly _enableUnfinishedFeatures: boolean,
|
||||
) {
|
||||
const menuItems = this._enableUnfinishedFeatures
|
||||
? PREFERENCES_MENU_ITEMS.slice()
|
||||
: READY_PREFERENCES_MENU_ITEMS.slice()
|
||||
|
||||
@@ -86,6 +86,7 @@ const DataBackups = ({ application, viewControllerManager }: Props) => {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const readFile = async (file: File): Promise<any> => {
|
||||
if (file.type === 'application/zip') {
|
||||
application.alerts.alert(STRING_IMPORTING_ZIP_FILE).catch(console.error)
|
||||
|
||||
@@ -16,7 +16,10 @@ export class TwoFactorAuth {
|
||||
private _status: TwoFactorStatus | 'fetching' = 'fetching'
|
||||
private _errorMessage: string | null
|
||||
|
||||
constructor(private readonly mfaProvider: MfaProvider, private readonly userProvider: UserProvider) {
|
||||
constructor(
|
||||
private readonly mfaProvider: MfaProvider,
|
||||
private readonly userProvider: UserProvider,
|
||||
) {
|
||||
this._errorMessage = null
|
||||
|
||||
makeAutoObservable<TwoFactorAuth, '_status' | '_errorMessage' | 'deactivateMfa' | 'startActivation'>(
|
||||
|
||||
@@ -156,7 +156,7 @@ const SuperNoteConverter = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={`Convert to ${name}`}
|
||||
title={`Convert to ${uiFeature.displayName}`}
|
||||
close={closeDialog}
|
||||
actions={modalActions}
|
||||
className={{
|
||||
|
||||
@@ -31,7 +31,9 @@ export function handleEditorChange(
|
||||
onChange?.(stringifiedEditorState, previewText)
|
||||
} catch (error) {
|
||||
window.alert(
|
||||
`An invalid change was made inside the Super editor. Your change was not saved. Please report this error to the team: ${error}`,
|
||||
`An invalid change was made inside the Super editor. Your change was not saved. Please report this error to the team: ${JSON.stringify(
|
||||
error,
|
||||
)}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@ export abstract class AbstractViewController<Event = void, EventData = void> {
|
||||
protected disposers: Disposer[] = []
|
||||
private eventObservers: ControllerEventObserver<Event, EventData>[] = []
|
||||
|
||||
constructor(public application: WebApplication, protected eventBus: InternalEventBusInterface) {}
|
||||
constructor(
|
||||
public application: WebApplication,
|
||||
protected eventBus: InternalEventBusInterface,
|
||||
) {}
|
||||
|
||||
protected async publishCrossControllerEventSync(name: CrossControllerEvent, data?: unknown): Promise<void> {
|
||||
await this.eventBus.publishSync({ type: name, payload: data }, InternalEventPublishStrategy.SEQUENCE)
|
||||
|
||||
@@ -8,7 +8,10 @@ export class PersistenceService {
|
||||
private unsubAppEventObserver: () => void
|
||||
private didHydrateOnce = false
|
||||
|
||||
constructor(private application: WebApplication, private eventBus: InternalEventBusInterface) {
|
||||
constructor(
|
||||
private application: WebApplication,
|
||||
private eventBus: InternalEventBusInterface,
|
||||
) {
|
||||
this.unsubAppEventObserver = this.application.addEventObserver(async (eventName) => {
|
||||
if (!this.application) {
|
||||
return
|
||||
|
||||
@@ -46,8 +46,8 @@ export class FilePreviewModalController {
|
||||
|
||||
deinit = () => {
|
||||
this.eventObservers.forEach((observer) => observer())
|
||||
;(this.currentFile as any) = undefined
|
||||
;(this.otherFiles as any) = undefined
|
||||
;(this.currentFile as unknown) = undefined
|
||||
;(this.otherFiles as unknown) = undefined
|
||||
}
|
||||
|
||||
setCurrentFile = (currentFile: FileItem) => {
|
||||
|
||||
@@ -27,7 +27,10 @@ export class ImportModalController {
|
||||
files: ImportModalFile[] = []
|
||||
importTag: SNTag | undefined = undefined
|
||||
|
||||
constructor(private application: WebApplication, private navigationController: NavigationController) {
|
||||
constructor(
|
||||
private application: WebApplication,
|
||||
private navigationController: NavigationController,
|
||||
) {
|
||||
makeObservable(this, {
|
||||
isVisible: observable,
|
||||
setIsVisible: action,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user