Compare commits

...
Author SHA1 Message Date
StandardNotes CI 789ed47774 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-09-12 17:43:46 +00:00
Antonella Sgarlatta 2338449425 chore: generate mfa secret in backend (#2930) [skip e2e]
* chore: get mfa secret from backend

* chore: remove unused code
2025-09-12 14:34:51 -03:00
StandardNotes CI d6840ba41c chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-09-04 19:21:57 +00:00
Antonella Sgarlatta 50c42eda50 chore: trigger release [skip e2e] 2025-09-04 16:12:45 -03:00
Antonella Sgarlatta ea3b65af04 chore: fix iOS workflow 2025-09-04 15:29:33 -03:00
Aman Harwara c964740d2b chore: fix search bar focus handling (#2932)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
2025-09-02 18:11:52 +05:30
28 changed files with 148 additions and 56 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ jobs:
defaults:
run:
working-directory: packages/mobile
runs-on: macos-latest
runs-on: macos-14
timeout-minutes: 90
steps:
- name: Checkout code
+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.546](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.545](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-04)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.544](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**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.544",
"version": "1.1.546",
"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.110.151](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.150](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-04)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.149](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**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.110.149",
"version": "3.110.151",
"license": "AGPL-3.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.58.209](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.208](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-04)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.207](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/mobile
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.58.207",
"version": "3.58.209",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.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.849](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.848](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-04)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.847](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.4.847",
"version": "1.4.849",
"license": "AGPL-3.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.
## [1.71.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/services
## [1.71.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.71.10",
"version": "1.71.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -1,7 +1,6 @@
export interface MfaServiceInterface {
isMfaActivated(): Promise<boolean>
generateMfaSecret(): Promise<string>
getOtpToken(secret: string): Promise<string>
enableMfa(secret: string, otpToken: string): Promise<void>
disableMfa(): Promise<void>
}
+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.209.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/snjs
## [2.209.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/snjs
@@ -1229,7 +1229,6 @@ export class Dependencies {
this.factory.set(TYPES.MfaService, () => {
return new MfaService(
this.get<SettingsService>(TYPES.SettingsService),
this.get<PureCryptoInterface>(TYPES.Crypto),
this.get<FeaturesService>(TYPES.FeaturesService),
this.get<ProtectionsClientInterface>(TYPES.ProtectionService),
this.get<EncryptionService>(TYPES.EncryptionService),
+12 -1
View File
@@ -77,7 +77,7 @@ import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
import { Paths } from './Paths'
import { DiskStorageService } from '../Storage/DiskStorageService'
import { UuidString } from '../../Types/UuidString'
import { SettingsServerInterface } from '../Settings/SettingsServerInterface'
import { SettingsServerInterface, MfaSecretResponse } from '../Settings/SettingsServerInterface'
import { Strings } from '@Lib/Strings'
import { AnyFeatureDescription } from '@standardnotes/features'
@@ -563,11 +563,13 @@ export class LegacyApiService
settingName: string,
settingValue: string | null,
sensitive: boolean,
totpToken?: string,
): Promise<HttpResponse<UpdateSettingResponse>> {
const params = {
name: settingName,
value: settingValue,
sensitive: sensitive,
...(totpToken && { totpToken }),
}
return this.tokenRefreshableRequest<UpdateSettingResponse>({
verb: HttpVerb.Put,
@@ -637,6 +639,15 @@ export class LegacyApiService
})
}
async getMfaSecret(userUuid: UuidString): Promise<HttpResponse<MfaSecretResponse>> {
return this.tokenRefreshableRequest<MfaSecretResponse>({
verb: HttpVerb.Get,
url: joinPaths(this.host, Paths.v1.mfaSecret(userUuid)),
authentication: this.getSessionAccessToken(),
fallbackErrorMessage: 'Failed to get MFA secret.',
})
}
public downloadFeatureUrl(url: string): Promise<HttpResponse> {
return this.request({
verb: HttpVerb.Get,
+1
View File
@@ -40,6 +40,7 @@ const ItemsPaths = {
const SettingsPaths = {
settings: (userUuid: string) => `/v1/users/${userUuid}/settings`,
setting: (userUuid: string, settingName: string) => `/v1/users/${userUuid}/settings/${settingName}`,
mfaSecret: (userUuid: string) => `/v1/users/${userUuid}/mfa-secret`,
subscriptionSetting: (userUuid: string, settingName: string) =>
`/v1/users/${userUuid}/subscription-settings/${settingName}`,
subscriptionSettings: (userUuid: string) => `/v1/users/${userUuid}/subscription-settings`,
+2 -24
View File
@@ -1,5 +1,4 @@
import { SettingsService } from '../Settings'
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
import { FeaturesService } from '../Features/FeaturesService'
import {
AbstractService,
@@ -7,7 +6,6 @@ import {
MfaServiceInterface,
ProtectionsClientInterface,
EncryptionService,
SignInStrings,
ChallengeValidation,
} from '@standardnotes/services'
import { SettingName } from '@standardnotes/domain-core'
@@ -16,7 +14,6 @@ import { SNRootKeyParams } from '@standardnotes/encryption'
export class MfaService extends AbstractService implements MfaServiceInterface {
constructor(
private settingsService: SettingsService,
private crypto: PureCryptoInterface,
private featuresService: FeaturesService,
private protections: ProtectionsClientInterface,
private encryption: EncryptionService,
@@ -25,14 +22,6 @@ export class MfaService extends AbstractService implements MfaServiceInterface {
super(internalEventBus)
}
private async saveMfaSetting(secret: string): Promise<void> {
return await this.settingsService.updateSetting(
SettingName.create(SettingName.NAMES.MfaSecret).getValue(),
secret,
true,
)
}
async isMfaActivated(): Promise<boolean> {
const mfaSetting = await this.settingsService.getDoesSensitiveSettingExist(
SettingName.create(SettingName.NAMES.MfaSecret).getValue(),
@@ -41,21 +30,11 @@ export class MfaService extends AbstractService implements MfaServiceInterface {
}
async generateMfaSecret(): Promise<string> {
return this.crypto.generateOtpSecret()
}
async getOtpToken(secret: string): Promise<string> {
return this.crypto.totpToken(secret, Date.now(), 6, 30)
return this.settingsService.generateMfaSecret()
}
async enableMfa(secret: string, otpToken: string): Promise<void> {
const otpTokenValid = otpToken != undefined && otpToken === (await this.getOtpToken(secret))
if (!otpTokenValid) {
throw new Error(SignInStrings.IncorrectMfa)
}
return this.saveMfaSetting(secret)
return this.settingsService.updateMfaSetting(secret, otpToken)
}
async disableMfa(): Promise<void> {
@@ -80,7 +59,6 @@ export class MfaService extends AbstractService implements MfaServiceInterface {
override deinit(): void {
;(this.settingsService as unknown) = undefined
;(this.crypto as unknown) = undefined
;(this.featuresService as unknown) = undefined
super.deinit()
}
@@ -42,8 +42,8 @@ export class SettingsService extends AbstractService implements SettingsClientIn
return this.provider.updateSubscriptionSetting(name, payload, sensitive)
}
async updateSetting(name: SettingName, payload: string, sensitive = false) {
return this.provider.updateSetting(name, payload, sensitive)
async updateSetting(name: SettingName, payload: string, sensitive = false, totpToken?: string) {
return this.provider.updateSetting(name, payload, sensitive, totpToken)
}
async getDoesSensitiveSettingExist(name: SettingName) {
@@ -54,6 +54,19 @@ export class SettingsService extends AbstractService implements SettingsClientIn
return this.provider.deleteSetting(name, serverPassword)
}
async generateMfaSecret(): Promise<string> {
return this.provider.getMfaSecret()
}
async updateMfaSetting(secret: string, totpToken: string): Promise<void> {
return this.provider.updateSetting(
SettingName.create(SettingName.NAMES.MfaSecret).getValue(),
secret,
true,
totpToken,
)
}
getEmailBackupFrequencyOptionLabel(frequency: EmailBackupFrequency): string {
return this.frequencyOptionsLabels[frequency]
}
@@ -9,9 +9,13 @@ export interface SettingsClientInterface {
getDoesSensitiveSettingExist(name: SettingName): Promise<boolean>
updateSetting(name: SettingName, payload: string, sensitive?: boolean): Promise<void>
updateSetting(name: SettingName, payload: string, sensitive?: boolean, totpToken?: string): Promise<void>
deleteSetting(name: SettingName, serverPassword?: string): Promise<void>
generateMfaSecret(): Promise<string>
updateMfaSetting(secret: string, totpToken: string): Promise<void>
getEmailBackupFrequencyOptionLabel(frequency: EmailBackupFrequency): string
}
@@ -102,8 +102,8 @@ export class SettingsGateway {
return response.data?.success ?? false
}
async updateSetting(name: SettingName, payload: string, sensitive: boolean): Promise<void> {
const response = await this.settingsApi.updateSetting(this.userUuid, name.value, payload, sensitive)
async updateSetting(name: SettingName, payload: string, sensitive: boolean, totpToken?: string): Promise<void> {
const response = await this.settingsApi.updateSetting(this.userUuid, name.value, payload, sensitive, totpToken)
if (isErrorResponse(response)) {
throw new Error(getErrorFromErrorResponse(response).message)
}
@@ -116,6 +116,14 @@ export class SettingsGateway {
}
}
async getMfaSecret(): Promise<string> {
const response = await this.settingsApi.getMfaSecret(this.userUuid)
if (isErrorResponse(response)) {
throw new Error(getErrorFromErrorResponse(response).message)
}
return response.data.secret
}
deinit() {
;(this.settingsApi as unknown) = undefined
;(this.userProvider as unknown) = undefined
@@ -7,6 +7,10 @@ import {
} from '@standardnotes/responses'
import { UuidString } from '@Lib/Types/UuidString'
export interface MfaSecretResponse {
secret: string
}
export interface SettingsServerInterface {
listSettings(userUuid: UuidString): Promise<HttpResponse<ListSettingsResponse>>
@@ -15,6 +19,7 @@ export interface SettingsServerInterface {
settingName: string,
settingValue: string,
sensitive: boolean,
totpToken?: string,
): Promise<HttpResponse<UpdateSettingResponse>>
getSetting(
@@ -32,6 +37,8 @@ export interface SettingsServerInterface {
sensitive: boolean,
): Promise<HttpResponse<UpdateSettingResponse>>
getMfaSecret(userUuid: UuidString): Promise<HttpResponse<MfaSecretResponse>>
deleteSetting(
userUuid: UuidString,
settingName: string,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.209.13",
"version": "2.209.14",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+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.
## [1.38.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.38.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/ui-services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.38.12",
"version": "1.38.13",
"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.198.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)
**Note:** Version bump only for package @standardnotes/web
## [3.198.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-04)
**Note:** Version bump only for package @standardnotes/web
## [3.198.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/web
+22
View File
@@ -1,5 +1,27 @@
{
"versions": [
{
"version": "3.198.19",
"title": "[3.198.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-12)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.18",
"title": "[3.198.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-09-04)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.17",
"title": "[3.198.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)",
+2 -2
View File
@@ -1,9 +1,9 @@
{
"name": "@standardnotes/web",
"version": "3.198.17",
"version": "3.198.19",
"license": "AGPL-3.0",
"main": "dist/app.js",
"author": "Standard Notes.",
"author": "Standard Notes",
"private": true,
"files": [
"dist"
@@ -1,6 +1,6 @@
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
import { KeyboardKey } from '@standardnotes/ui-services'
import { useState, useCallback, KeyboardEventHandler, useRef } from 'react'
import { useCallback, KeyboardEventHandler, useRef } from 'react'
import SearchOptions from '@/Components/SearchOptions/SearchOptions'
import { SearchOptionsController } from '@/Controllers/SearchOptionsController'
import Icon from '../Icon/Icon'
@@ -8,6 +8,7 @@ import DecoratedInput from '../Input/DecoratedInput'
import { observer } from 'mobx-react-lite'
import ClearInputButton from '../ClearInputButton/ClearInputButton'
import { ElementIds } from '@/Constants/ElementIDs'
import { classNames } from '@standardnotes/snjs'
type Props = {
itemListController: ItemListController
@@ -16,12 +17,11 @@ type Props = {
}
const SearchBar = ({ itemListController, searchOptionsController, hideOptions = false }: Props) => {
const searchBarRef = useRef<HTMLDivElement>(null)
const searchInputRef = useRef<HTMLInputElement>(null)
const { noteFilterText, setNoteFilterText, clearFilterText, onFilterEnter } = itemListController
const [focusedSearch, setFocusedSearch] = useState(false)
const onNoteFilterTextChange = useCallback(
(text: string) => {
setNoteFilterText(text)
@@ -38,16 +38,13 @@ const SearchBar = ({ itemListController, searchOptionsController, hideOptions =
[onFilterEnter],
)
const onSearchFocus = useCallback(() => setFocusedSearch(true), [])
const onSearchBlur = useCallback(() => setFocusedSearch(false), [])
const onClearSearch = useCallback(() => {
clearFilterText()
searchInputRef.current?.focus()
}, [clearFilterText])
return (
<div className="pb-0.5 pt-3" role="search">
<div className="group pb-0.5 pt-3" role="search" ref={searchBarRef}>
<DecoratedInput
autocomplete={false}
id={ElementIds.SearchBar}
@@ -58,20 +55,21 @@ const SearchBar = ({ itemListController, searchOptionsController, hideOptions =
placeholder={'Search...'}
value={noteFilterText}
ref={searchInputRef}
onBlur={onSearchBlur}
onChange={onNoteFilterTextChange}
onFocus={onSearchFocus}
onKeyUp={onNoteFilterKeyUp}
left={[<Icon type="search" className="mr-1 h-4.5 w-4.5 flex-shrink-0 text-passive-1" />]}
right={[noteFilterText && <ClearInputButton onClick={onClearSearch} />]}
roundedFull
/>
{(focusedSearch || noteFilterText) && !hideOptions && (
<div className="animate-fade-from-top">
<SearchOptions searchOptions={searchOptionsController} />
</div>
)}
<div
className={classNames(
'animate-fade-from-top',
hideOptions ? 'hidden' : !noteFilterText && 'hidden group-focus-within:flex',
)}
>
<SearchOptions searchOptions={searchOptionsController} />
</div>
</div>
)
}