Compare commits

...
24 changed files with 352 additions and 270 deletions
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.137](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.136](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.135](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)
**Note:** Version bump only for package @standardnotes/clipper
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/clipper",
"description": "Web clipper browser extension for Standard Notes",
"version": "1.1.135",
"version": "1.1.137",
"private": true,
"scripts": {
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.108.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.67](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)
**Note:** Version bump only for package @standardnotes/desktop
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.108.66",
"version": "3.108.68",
"license": "CC BY-NC-SA 4.0",
"author": "Standard Notes.",
"private": true,
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.56.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.56.46",
"version": "3.56.48",
"author": "Standard Notes.",
"private": true,
"license": "CC BY-NC-SA 4.0",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.4.420](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.419](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.418](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.4.418",
"version": "1.4.420",
"license": "CC BY-NC-SA 4.0",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.202.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/snjs
## [2.202.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)
**Note:** Version bump only for package @standardnotes/snjs
@@ -53,6 +53,7 @@ export const BaseTests = [
'preferences.test.js',
'files.test.js',
'session.test.js',
'session-invalidation.test.js',
'subscriptions.test.js',
'recovery.test.js',
]
@@ -132,63 +132,6 @@ describe('key recovery service', function () {
await context.deinit()
})
it('recovered keys with key params not matching servers should not be synced if local root key does not match server', async function () {
/**
* Assume Application A has been through these states:
* 1. Registration + Items Key A + Root Key A
* 2. Password change + Items Key B + Root Key B
* 3. Password change + Items Key C + Root Key C + Failure to correctly re-encrypt Items Key A and B with Root Key C
*
* Application B is not correctly in sync, and is only at State 1 (Registration + Items Key A)
*
* Application B receives Items Key B of Root Key B but for whatever reason ignores Items Key C of Root Key C.
*
* When it recovers Items Key B, it should not re-upload it to the server, because Application B's Root Key is not
* the current account's root key.
*/
const contextA = await Factory.createAppContextWithFakeCrypto()
await contextA.launch()
await contextA.register()
contextA.preventKeyRecoveryOfKeys()
const contextB = await Factory.createAppContextWithFakeCrypto('app-b', contextA.email, contextA.password)
await contextB.launch()
await contextB.signIn()
await contextA.changePassword('new-password-1')
const itemsKeyARootKeyB = contextA.itemsKeys[0]
const itemsKeyBRootKeyB = contextA.itemsKeys[1]
contextA.disableSyncingOfItems([itemsKeyARootKeyB.uuid, itemsKeyBRootKeyB.uuid])
await contextA.changePassword('new-password-2')
const itemsKeyCRootKeyC = contextA.itemsKeys[2]
contextB.disableKeyRecoveryServerSignIn()
contextB.preventKeyRecoveryOfKeys([itemsKeyCRootKeyC.uuid])
contextB.respondToAccountPasswordChallengeWith('new-password-1')
const recoveryPromise = Promise.all([
contextB.resolveWhenKeyRecovered(itemsKeyARootKeyB.uuid),
contextB.resolveWhenKeyRecovered(itemsKeyBRootKeyB.uuid),
])
const observedDirtyItemUuids = []
contextB.spyOnChangedItems((changed) => {
const dirty = changed.filter((i) => i.dirty)
extendArray(observedDirtyItemUuids, Uuids(dirty))
})
await contextB.sync()
await recoveryPromise
expect(observedDirtyItemUuids.includes(itemsKeyARootKeyB.uuid)).to.equal(false)
expect(observedDirtyItemUuids.includes(itemsKeyBRootKeyB.uuid)).to.equal(false)
await contextA.deinit()
await contextB.deinit()
})
it('when encountering many undecryptable items key with same key params, should only prompt once', async function () {
const namespace = Factory.randomString()
const unassociatedPassword = 'randfoo'
@@ -251,111 +194,6 @@ describe('key recovery service', function () {
await context.deinit()
})
it('when changing password on client B, client A should perform recovery flow', async function () {
const contextA = await Factory.createAppContextWithFakeCrypto()
await contextA.launch()
await contextA.register()
const originalItemsKey = contextA.application.items.getDisplayableItemsKeys()[0]
const contextB = await Factory.createAppContextWithFakeCrypto(
'another-namespace',
contextA.email,
contextA.password,
)
contextB.ignoreChallenges()
await contextB.launch()
await contextB.signIn()
const newPassword = `${Math.random()}`
const result = await contextB.application.changePassword(contextA.password, newPassword)
expect(result.error).to.not.be.ok
expect(contextB.application.items.getAnyItems(ContentType.TYPES.ItemsKey).length).to.equal(2)
const newItemsKey = contextB.application.items
.getDisplayableItemsKeys()
.find((k) => k.uuid !== originalItemsKey.uuid)
const note = await Factory.createSyncedNote(contextB.application)
const recoveryPromise = contextA.resolveWhenKeyRecovered(newItemsKey.uuid)
contextA.password = newPassword
await contextA.sync(syncOptions)
await recoveryPromise
/** Same previously errored key should now no longer be errored, */
expect(contextA.application.items.getAnyItems(ContentType.TYPES.ItemsKey).length).to.equal(2)
for (const key of contextA.application.items.getDisplayableItemsKeys()) {
expect(key.errorDecrypting).to.not.be.ok
}
const aKey = await contextA.application.encryption.getRootKey()
const bKey = await contextB.application.encryption.getRootKey()
expect(aKey.compare(bKey)).to.equal(true)
expect(contextA.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
expect(contextB.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
expect(contextA.application.sync.isOutOfSync()).to.equal(false)
expect(contextB.application.sync.isOutOfSync()).to.equal(false)
await contextA.deinit()
await contextB.deinit()
}).timeout(80000)
it('when items key associated with item is errored, item should be marked waiting for key', async function () {
const namespace = Factory.randomString()
const newPassword = `${Math.random()}`
const contextA = await Factory.createAppContextWithFakeCrypto(namespace)
const appA = contextA.application
await appA.prepareForLaunch({ receiveChallenge: () => {} })
await appA.launch(true)
await Factory.registerUserToApplication({
application: appA,
email: contextA.email,
password: contextA.password,
})
expect(appA.items.getItems(ContentType.TYPES.ItemsKey).length).to.equal(1)
/** Create simultaneous appB signed into same account */
const appB = await Factory.createApplicationWithFakeCrypto('another-namespace')
await appB.prepareForLaunch({ receiveChallenge: () => {} })
await appB.launch(true)
await Factory.loginToApplication({
application: appB,
email: contextA.email,
password: contextA.password,
})
/** Change password on appB */
await appB.changePassword(contextA.password, newPassword)
const note = await Factory.createSyncedNote(appB)
await appB.sync.sync()
/** We expect the item in appA to be errored at this point, but we do not want it to recover */
await appA.sync.sync()
expect(appA.payloads.findOne(note.uuid).waitingForKey).to.equal(true)
console.warn('Expecting exceptions below as we destroy app during key recovery')
await Factory.safeDeinit(appA)
await Factory.safeDeinit(appB)
const recreatedAppA = await Factory.createApplicationWithFakeCrypto(namespace)
await recreatedAppA.prepareForLaunch({ receiveChallenge: () => {} })
await recreatedAppA.launch(true)
expect(recreatedAppA.payloads.findOne(note.uuid).errorDecrypting).to.equal(true)
expect(recreatedAppA.payloads.findOne(note.uuid).waitingForKey).to.equal(true)
await Factory.safeDeinit(recreatedAppA)
})
it('when client key params differ from server, and no matching items key exists to compare against, should perform sign in flow', async function () {
/**
* When a user changes password/email on client A, client B must update their root key to the new one.
-44
View File
@@ -599,50 +599,6 @@ describe('keys', function () {
await Factory.safeDeinit(recreatedApp)
})
it('errored second client should not upload its items keys', async function () {
/**
* The original source of this issue was that when changing password on client A and syncing with B,
* the newly encrypted items key retrieved on B would be included as "ignored", so its timestamps
* would not be emitted, and thus the application would be in sync. The app would then download
* the items key independently, and make duplicates erroneously.
*/
const contextA = this.context
const email = Utils.generateUuid()
const password = Utils.generateUuid()
await Factory.registerUserToApplication({
application: contextA.application,
email,
password: password,
})
const contextB = await Factory.createAppContext({ email, password })
await contextB.launch()
await contextB.signIn()
contextA.ignoreChallenges()
contextB.ignoreChallenges()
const newPassword = Utils.generateUuid()
await contextA.application.user.changeCredentials({
currentPassword: password,
newPassword: newPassword,
origination: KeyParamsOrigination.PasswordChange,
})
await contextB.syncWithIntegrityCheck()
await contextA.syncWithIntegrityCheck()
const clientAUndecryptables = contextA.keyRecovery.getUndecryptables()
const clientBUndecryptables = contextB.keyRecovery.getUndecryptables()
expect(Object.keys(clientBUndecryptables).length).to.equal(1)
expect(Object.keys(clientAUndecryptables).length).to.equal(0)
await contextB.deinit()
})
describe('changing password on 003 account while signed into 004 client', function () {
/**
* When an 004 client signs into 003 account, it creates a root key based items key.
@@ -0,0 +1,267 @@
describe.skip('session invalidation tests to revisit', function () {
this.timeout(Factory.TwentySecondTimeout)
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
}
beforeEach(function () {
localStorage.clear()
})
afterEach(function () {
localStorage.clear()
})
it('recovered keys with key params not matching servers should not be synced if local root key does not match server', async function () {
/**
* Assume Application A has been through these states:
* 1. Registration + Items Key A + Root Key A
* 2. Password change + Items Key B + Root Key B
* 3. Password change + Items Key C + Root Key C + Failure to correctly re-encrypt Items Key A and B with Root Key C
*
* Application B is not correctly in sync, and is only at State 1 (Registration + Items Key A)
*
* Application B receives Items Key B of Root Key B but for whatever reason ignores Items Key C of Root Key C.
*
* When it recovers Items Key B, it should not re-upload it to the server, because Application B's Root Key is not
* the current account's root key.
*/
const contextA = await Factory.createAppContextWithFakeCrypto()
await contextA.launch()
await contextA.register()
contextA.preventKeyRecoveryOfKeys()
const contextB = await Factory.createAppContextWithFakeCrypto('app-b', contextA.email, contextA.password)
await contextB.launch()
await contextB.signIn()
await contextA.changePassword('new-password-1')
const itemsKeyARootKeyB = contextA.itemsKeys[0]
const itemsKeyBRootKeyB = contextA.itemsKeys[1]
contextA.disableSyncingOfItems([itemsKeyARootKeyB.uuid, itemsKeyBRootKeyB.uuid])
await contextA.changePassword('new-password-2')
const itemsKeyCRootKeyC = contextA.itemsKeys[2]
contextB.disableKeyRecoveryServerSignIn()
contextB.preventKeyRecoveryOfKeys([itemsKeyCRootKeyC.uuid])
contextB.respondToAccountPasswordChallengeWith('new-password-1')
const recoveryPromise = Promise.all([
contextB.resolveWhenKeyRecovered(itemsKeyARootKeyB.uuid),
contextB.resolveWhenKeyRecovered(itemsKeyBRootKeyB.uuid),
])
const observedDirtyItemUuids = []
contextB.spyOnChangedItems((changed) => {
const dirty = changed.filter((i) => i.dirty)
extendArray(observedDirtyItemUuids, Uuids(dirty))
})
await contextB.sync()
await recoveryPromise
expect(observedDirtyItemUuids.includes(itemsKeyARootKeyB.uuid)).to.equal(false)
expect(observedDirtyItemUuids.includes(itemsKeyBRootKeyB.uuid)).to.equal(false)
await contextA.deinit()
await contextB.deinit()
})
it('when changing password on client B, client A should perform recovery flow', async function () {
const contextA = await Factory.createAppContextWithFakeCrypto()
await contextA.launch()
await contextA.register()
const originalItemsKey = contextA.application.items.getDisplayableItemsKeys()[0]
const contextB = await Factory.createAppContextWithFakeCrypto(
'another-namespace',
contextA.email,
contextA.password,
)
contextB.ignoreChallenges()
await contextB.launch()
await contextB.signIn()
const newPassword = `${Math.random()}`
const result = await contextB.application.changePassword(contextA.password, newPassword)
expect(result.error).to.not.be.ok
expect(contextB.application.items.getAnyItems(ContentType.TYPES.ItemsKey).length).to.equal(2)
const newItemsKey = contextB.application.items
.getDisplayableItemsKeys()
.find((k) => k.uuid !== originalItemsKey.uuid)
const note = await Factory.createSyncedNote(contextB.application)
const recoveryPromise = contextA.resolveWhenKeyRecovered(newItemsKey.uuid)
contextA.password = newPassword
await contextA.sync(syncOptions)
await recoveryPromise
/** Same previously errored key should now no longer be errored, */
expect(contextA.application.items.getAnyItems(ContentType.TYPES.ItemsKey).length).to.equal(2)
for (const key of contextA.application.items.getDisplayableItemsKeys()) {
expect(key.errorDecrypting).to.not.be.ok
}
const aKey = await contextA.application.encryption.getRootKey()
const bKey = await contextB.application.encryption.getRootKey()
expect(aKey.compare(bKey)).to.equal(true)
expect(contextA.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
expect(contextB.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
expect(contextA.application.sync.isOutOfSync()).to.equal(false)
expect(contextB.application.sync.isOutOfSync()).to.equal(false)
await contextA.deinit()
await contextB.deinit()
}).timeout(80000)
it('when items key associated with item is errored, item should be marked waiting for key', async function () {
const namespace = Factory.randomString()
const newPassword = `${Math.random()}`
const contextA = await Factory.createAppContextWithFakeCrypto(namespace)
const appA = contextA.application
await appA.prepareForLaunch({ receiveChallenge: () => {} })
await appA.launch(true)
await Factory.registerUserToApplication({
application: appA,
email: contextA.email,
password: contextA.password,
})
expect(appA.items.getItems(ContentType.TYPES.ItemsKey).length).to.equal(1)
/** Create simultaneous appB signed into same account */
const appB = await Factory.createApplicationWithFakeCrypto('another-namespace')
await appB.prepareForLaunch({ receiveChallenge: () => {} })
await appB.launch(true)
await Factory.loginToApplication({
application: appB,
email: contextA.email,
password: contextA.password,
})
/** Change password on appB */
await appB.changePassword(contextA.password, newPassword)
const note = await Factory.createSyncedNote(appB)
await appB.sync.sync()
/** We expect the item in appA to be errored at this point, but we do not want it to recover */
await appA.sync.sync()
expect(appA.payloads.findOne(note.uuid).waitingForKey).to.equal(true)
console.warn('Expecting exceptions below as we destroy app during key recovery')
await Factory.safeDeinit(appA)
await Factory.safeDeinit(appB)
const recreatedAppA = await Factory.createApplicationWithFakeCrypto(namespace)
await recreatedAppA.prepareForLaunch({ receiveChallenge: () => {} })
await recreatedAppA.launch(true)
expect(recreatedAppA.payloads.findOne(note.uuid).errorDecrypting).to.equal(true)
expect(recreatedAppA.payloads.findOne(note.uuid).waitingForKey).to.equal(true)
await Factory.safeDeinit(recreatedAppA)
})
it('errored second client should not upload its items keys', async function () {
/**
* The original source of this issue was that when changing password on client A and syncing with B,
* the newly encrypted items key retrieved on B would be included as "ignored", so its timestamps
* would not be emitted, and thus the application would be in sync. The app would then download
* the items key independently, and make duplicates erroneously.
*/
const contextA = this.context
const email = Utils.generateUuid()
const password = Utils.generateUuid()
await Factory.registerUserToApplication({
application: contextA.application,
email,
password: password,
})
const contextB = await Factory.createAppContext({ email, password })
await contextB.launch()
await contextB.signIn()
contextA.ignoreChallenges()
contextB.ignoreChallenges()
const newPassword = Utils.generateUuid()
await contextA.application.user.changeCredentials({
currentPassword: password,
newPassword: newPassword,
origination: KeyParamsOrigination.PasswordChange,
})
await contextB.syncWithIntegrityCheck()
await contextA.syncWithIntegrityCheck()
const clientAUndecryptables = contextA.keyRecovery.getUndecryptables()
const clientBUndecryptables = contextB.keyRecovery.getUndecryptables()
expect(Object.keys(clientBUndecryptables).length).to.equal(1)
expect(Object.keys(clientAUndecryptables).length).to.equal(0)
await contextB.deinit()
})
it('changing password on one client should not invalidate other sessions', async function () {
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
})
const appA = await Factory.createApplicationWithFakeCrypto(Factory.randomString())
await appA.prepareForLaunch({})
await appA.launch(true)
const email = `${Math.random()}`
const password = `${Math.random()}`
await Factory.registerUserToApplication({
application: appA,
email: email,
password: password,
})
/** Create simultaneous appB signed into same account */
const appB = await Factory.createApplicationWithFakeCrypto('another-namespace')
await appB.prepareForLaunch({})
await appB.launch(true)
await Factory.loginToApplication({
application: appB,
email: email,
password: password,
})
/** Change password on appB */
const newPassword = 'random'
await appB.changePassword(password, newPassword)
/** Create an item and sync it */
const note = await Factory.createSyncedNote(appB)
/** Expect appA session to still be valid */
await appA.sync.sync()
expect(appA.items.findItem(note.uuid)).to.be.ok
await Factory.safeDeinit(appA)
await Factory.safeDeinit(appB)
})
})
-45
View File
@@ -483,51 +483,6 @@ describe('server session', function () {
}
}).timeout(Factory.TwentySecondTimeout)
it('changing password on one client should not invalidate other sessions', async function () {
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
})
const appA = await Factory.createApplicationWithFakeCrypto(Factory.randomString())
await appA.prepareForLaunch({})
await appA.launch(true)
const email = `${Math.random()}`
const password = `${Math.random()}`
await Factory.registerUserToApplication({
application: appA,
email: email,
password: password,
})
/** Create simultaneous appB signed into same account */
const appB = await Factory.createApplicationWithFakeCrypto('another-namespace')
await appB.prepareForLaunch({})
await appB.launch(true)
await Factory.loginToApplication({
application: appB,
email: email,
password: password,
})
/** Change password on appB */
const newPassword = 'random'
await appB.changePassword(password, newPassword)
/** Create an item and sync it */
const note = await Factory.createSyncedNote(appB)
/** Expect appA session to still be valid */
await appA.sync.sync()
expect(appA.items.findItem(note.uuid)).to.be.ok
await Factory.safeDeinit(appA)
await Factory.safeDeinit(appB)
})
it('should prompt user for account password and sign back in on invalid session', async function () {
await Factory.registerUserToApplication({
application: this.application,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.202.28",
"version": "2.202.29",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.167.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/web
## [3.167.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)
**Note:** Version bump only for package @standardnotes/web
## [3.167.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)
### Bug Fixes
+22
View File
@@ -1,5 +1,27 @@
{
"versions": [
{
"version": "3.167.35",
"title": "[3.167.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.167.34",
"title": "[3.167.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-04)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.167.33",
"title": "[3.167.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-03)",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.167.33",
"version": "3.167.35",
"license": "CC BY-NC-SA 4.0",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -27,7 +27,7 @@ const AlertDialog = ({
<Dialog
store={dialog}
role="alertdialog"
className="fixed left-0 top-0 z-modal h-full w-full"
className="fixed left-0 top-0 z-modal h-full w-full flex items-center justify-center"
modal={false}
portal={true}
preventBodyScroll={true}
@@ -40,7 +40,7 @@ const AlertDialog = ({
/>
<div
className={classNames(
'absolute left-1/2 top-1/2 z-[1] w-[95vw] -translate-x-1/2 -translate-y-1/2 rounded border border-border bg-default px-6 py-5 shadow-xl md:w-auto',
'w-[95vw] rounded border border-border bg-default px-6 py-5 shadow-xl md:w-auto',
!className?.includes('max-w-') && 'max-w-[600px]',
className,
)}
@@ -104,8 +104,7 @@ const Modal = ({
/>
<div
className={classNames(
'absolute z-[1] m-0 flex h-full w-full flex-col border-solid border-border bg-default p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
'md:left-1/2 md:top-1/2 md:-translate-x-1/2 md:-translate-y-1/2 md:transform',
'z-[1] m-0 flex h-full w-full flex-col border-solid border-border bg-default p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
className?.content,
)}
>
@@ -42,7 +42,7 @@ const ModalOverlay = forwardRef(
return (
<Dialog
tabIndex={0}
className="fixed left-0 top-0 z-modal h-full w-full"
className="fixed flex items-center justify-center left-0 top-0 z-modal h-full w-full"
ref={mergeRefs([setElement, addCloseMethod, ref])}
store={dialog}
modal={false}
@@ -29,8 +29,8 @@ const getStylesFromRect = (
return {
willChange: 'transform',
'--translate-x': `${shouldApplyMobileWidth ? marginForMobile / 2 : rect.x}px`,
'--translate-y': `${rect.y}px`,
'--translate-x': `${shouldApplyMobileWidth ? marginForMobile / 2 : Math.floor(rect.x)}px`,
'--translate-y': `${Math.floor(rect.y)}px`,
'--offset': `${options.offset}px`,
transform: 'translate(var(--translate-x), var(--translate-y))',
visibility: 'visible',
@@ -19,8 +19,8 @@ export const getAdjustedStylesForNonPortalPopover = (
const parentRect = absoluteParent.getBoundingClientRect()
const adjustedTranslateX = parsedTranslateX - parentRect.left
const adjustedTranslateY = parsedTranslateY - parentRect.top
const adjustedTranslateX = Math.floor(parsedTranslateX - parentRect.left)
const adjustedTranslateY = Math.floor(parsedTranslateY - parentRect.top)
return {
...styles,
@@ -8,18 +8,18 @@ export const movePopoverToFitInsideRect = (popoverElement: HTMLElement, rect: DO
const overflows = getOverflows(popoverRect, rect)
if (overflows['top'] > 0) {
popoverElement.style.setProperty('--translate-y', `${y + overflows['top'] + offset}px`)
popoverElement.style.setProperty('--translate-y', `${Math.floor(y + overflows['top'] + offset)}px`)
}
if (overflows['bottom'] > 0) {
popoverElement.style.setProperty('--translate-y', `${y - overflows['bottom'] - offset}px`)
popoverElement.style.setProperty('--translate-y', `${Math.floor(y - overflows['bottom'] - offset)}px`)
}
if (overflows['left'] > 0) {
popoverElement.style.setProperty('--translate-x', `${x + overflows['left'] + offset}px`)
popoverElement.style.setProperty('--translate-x', `${Math.floor(x + overflows['left'] + offset)}px`)
}
if (overflows['right'] > 0) {
popoverElement.style.setProperty('--translate-x', `${x - overflows['right'] - offset}px`)
popoverElement.style.setProperty('--translate-x', `${Math.floor(x - overflows['right'] - offset)}px`)
}
}