mirror of
https://github.com/standardnotes/app
synced 2026-09-13 00:45:26 -04:00
Compare commits
73
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4f9a18135 | ||
|
|
65c16ed246 | ||
|
|
852ddc677d | ||
|
|
17458b61d1 | ||
|
|
03da45537d | ||
|
|
7332f10ff4 | ||
|
|
b6eda707bd | ||
|
|
a37e095907 | ||
|
|
ef81e9d97e | ||
|
|
c6a31f209d | ||
|
|
292153333f | ||
|
|
6cef772212 | ||
|
|
f4ab9b0d97 | ||
|
|
73eba38c14 | ||
|
|
4b19076f9b | ||
|
|
da9c412703 | ||
|
|
9784ff0173 | ||
|
|
d8df19b0bd | ||
|
|
da16a779ce | ||
|
|
473fb6be53 | ||
|
|
d5cac8e32d | ||
|
|
45ca99c627 | ||
|
|
8a6e123fbc | ||
|
|
914c444349 | ||
|
|
bf8ad837ef | ||
|
|
e3ae421f7c | ||
|
|
a162294d04 | ||
|
|
f0613e7af5 | ||
|
|
7967ddead7 | ||
|
|
f868989bb5 | ||
|
|
eb5e5e11e0 | ||
|
|
0d1831ea49 | ||
|
|
a22000242a | ||
|
|
4068d5b480 | ||
|
|
fd0d08c153 | ||
|
|
adef74f23f | ||
|
|
b90c725f96 | ||
|
|
74b459cae0 | ||
|
|
c1e9a7fe40 | ||
|
|
edf8de4468 | ||
|
|
bb81c8acfc | ||
|
|
414a2dda0b | ||
|
|
45c661c136 | ||
|
|
c5ca4a9857 | ||
|
|
56813909bb | ||
|
|
7a4172ad11 | ||
|
|
e97e788b5f | ||
|
|
20a9ef0dad | ||
|
|
670f27b9cd | ||
|
|
f45d854006 | ||
|
|
5043b4c110 | ||
|
|
e1981f4eae | ||
|
|
3fb6d10a7f | ||
|
|
498cd1b27c | ||
|
|
6d872cd45a | ||
|
|
9e2d496804 | ||
|
|
7febc1fac6 | ||
|
|
6f571936c3 | ||
|
|
065f3562f4 | ||
|
|
41f542d1c5 | ||
|
|
94840a7afb | ||
|
|
fb19b37d5b | ||
|
|
3b2f761661 | ||
|
|
b28b59e4a0 | ||
|
|
9238759d38 | ||
|
|
d2404ba276 | ||
|
|
7301acd36c | ||
|
|
bf997e356c | ||
|
|
c151c3c6d7 | ||
|
|
6af7f66f46 | ||
|
|
1d0e8cfc7f | ||
|
|
f3f5c63185 | ||
|
|
1651a24370 |
@@ -103,6 +103,44 @@ jobs:
|
||||
trigger_workflow: true
|
||||
wait_workflow: true
|
||||
|
||||
publish-web-docker:
|
||||
name: Build and publish Docker Image for Web App
|
||||
needs: [e2e-base, e2e-vaults]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_PAT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Build
|
||||
run: yarn build:web
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Publish SNJS Docker image for E2E testing
|
||||
run: |
|
||||
cd packages/web
|
||||
docker build -t standardnotes/web:${{ github.sha }} .
|
||||
docker tag standardnotes/web:${{ github.sha }} standardnotes/web:latest
|
||||
docker push standardnotes/web:${{ github.sha }}
|
||||
docker push standardnotes/web:latest
|
||||
|
||||
publish:
|
||||
name: Publish to NPM
|
||||
needs: [e2e-base, e2e-vaults]
|
||||
|
||||
@@ -49,11 +49,12 @@ Questions? Find answers on our [Help page](https://standardnotes.com/help).
|
||||
|
||||
Our web app is compiled into a folder of static HTML, JS, and CSS files. You can serve these files behind a web server to get started:
|
||||
|
||||
1. Clone the repo
|
||||
2. `cd packages/web`
|
||||
3. `yarn build`
|
||||
4. `cd dist`
|
||||
5. You can then use Python to serve this folder over http: `python -m http.server 8080`
|
||||
1. `git clone https://github.com/standardnotes/app.git`
|
||||
2. `cd app`
|
||||
3. `yarn install`
|
||||
4. `yarn build:web`
|
||||
5. `cd packages/web`
|
||||
6. You can then use Python to serve this folder over http: `python -m http.server 8080`
|
||||
|
||||
You can now access the app at `http://localhost:8080`.
|
||||
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.87](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.86](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.85](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.84](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.83](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use API v0 on iOS ([#2858](https://github.com/standardnotes/app/issues/2858)) [skip e2e] ([3b2f761](https://github.com/standardnotes/app/commit/3b2f76166126a5b11f35b64aacefa37618622c3d))
|
||||
|
||||
## [1.26.82](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.81](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.26.81",
|
||||
"version": "1.26.87",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export enum ApiVersion {
|
||||
v0 = '20200115',
|
||||
v1 = '20240226',
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ import { AuthApiServiceInterface } from './AuthApiServiceInterface'
|
||||
export class AuthApiService implements AuthApiServiceInterface {
|
||||
private operationsInProgress: Map<AuthApiOperations, boolean>
|
||||
|
||||
constructor(private authServer: AuthServerInterface) {
|
||||
constructor(
|
||||
private authServer: AuthServerInterface,
|
||||
private apiVersion: ApiVersion,
|
||||
) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
|
||||
@@ -50,7 +53,7 @@ export class AuthApiService implements AuthApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.authServer.recoveryKeyParams({
|
||||
api_version: ApiVersion.v0,
|
||||
api_version: this.apiVersion,
|
||||
code_challenge: dto.codeChallenge,
|
||||
recovery_codes: dto.recoveryCodes,
|
||||
username: dto.username,
|
||||
@@ -69,6 +72,7 @@ export class AuthApiService implements AuthApiServiceInterface {
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
hvmToken?: string
|
||||
}): Promise<HttpResponse<SignInWithRecoveryCodesResponseBody>> {
|
||||
if (this.operationsInProgress.get(AuthApiOperations.SignInWithRecoveryCodes)) {
|
||||
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||
@@ -78,11 +82,12 @@ export class AuthApiService implements AuthApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.authServer.signInWithRecoveryCodes({
|
||||
api_version: ApiVersion.v0,
|
||||
api_version: this.apiVersion,
|
||||
code_verifier: dto.codeVerifier,
|
||||
password: dto.password,
|
||||
recovery_codes: dto.recoveryCodes,
|
||||
username: dto.username,
|
||||
hvm_token: dto.hvmToken,
|
||||
})
|
||||
|
||||
return response
|
||||
|
||||
@@ -17,5 +17,6 @@ export interface AuthApiServiceInterface {
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
hvmToken?: string
|
||||
}): Promise<HttpResponse<SignInWithRecoveryCodesResponseBody>>
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@ import { GetUserSubscriptionRequestParams } from '../../Request/Subscription/Get
|
||||
export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
private operationsInProgress: Map<SubscriptionApiOperations, boolean>
|
||||
|
||||
constructor(private subscriptionServer: SubscriptionServerInterface) {
|
||||
constructor(
|
||||
private subscriptionServer: SubscriptionServerInterface,
|
||||
private apiVersion: ApiVersion,
|
||||
) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
|
||||
@@ -36,7 +39,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.subscriptionServer.listInvites({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: this.apiVersion,
|
||||
})
|
||||
|
||||
return response
|
||||
@@ -56,7 +59,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.subscriptionServer.cancelInvite({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: this.apiVersion,
|
||||
inviteUuid,
|
||||
})
|
||||
|
||||
@@ -77,7 +80,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.subscriptionServer.invite({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: this.apiVersion,
|
||||
identifier: inviteeEmail,
|
||||
})
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ export class UserApiService implements UserApiServiceInterface {
|
||||
constructor(
|
||||
private userServer: UserServerInterface,
|
||||
private userRequestServer: UserRequestServerInterface,
|
||||
private apiVersion: ApiVersion,
|
||||
) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
@@ -65,6 +66,7 @@ export class UserApiService implements UserApiServiceInterface {
|
||||
async register(registerDTO: {
|
||||
email: string
|
||||
serverPassword: string
|
||||
hvmToken?: string
|
||||
keyParams: RootKeyParamsInterface
|
||||
ephemeral: boolean
|
||||
}): Promise<HttpResponse<UserRegistrationResponseBody>> {
|
||||
@@ -72,9 +74,10 @@ export class UserApiService implements UserApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.userServer.register({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: this.apiVersion,
|
||||
password: registerDTO.serverPassword,
|
||||
email: registerDTO.email,
|
||||
hvm_token: registerDTO.hvmToken,
|
||||
ephemeral: registerDTO.ephemeral,
|
||||
...registerDTO.keyParams.getPortableValue(),
|
||||
})
|
||||
@@ -92,7 +95,7 @@ export class UserApiService implements UserApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.userServer.update({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: this.apiVersion,
|
||||
user_uuid: updateDTO.userUuid,
|
||||
})
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface UserApiServiceInterface {
|
||||
register(registerDTO: {
|
||||
email: string
|
||||
serverPassword: string
|
||||
hvmToken?: string
|
||||
keyParams: RootKeyParamsInterface
|
||||
ephemeral: boolean
|
||||
}): Promise<HttpResponse<UserRegistrationResponseBody>>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LoggerInterface, joinPaths, sleep } from '@standardnotes/utils'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
import { LegacySession, Session, SessionToken } from '@standardnotes/domain-core'
|
||||
import { LegacySession, Result, Session, SessionToken } from '@standardnotes/domain-core'
|
||||
import {
|
||||
HttpStatusCode,
|
||||
HttpRequestParams,
|
||||
@@ -9,9 +9,11 @@ import {
|
||||
HttpResponse,
|
||||
HttpResponseMeta,
|
||||
isErrorResponse,
|
||||
ApiEndpointParam,
|
||||
} from '@standardnotes/responses'
|
||||
import { HttpServiceInterface } from './HttpServiceInterface'
|
||||
|
||||
import { ApiVersion } from '../Api'
|
||||
import { Paths } from '../Server/Auth/Paths'
|
||||
import { SessionRefreshResponseBody } from '../Response/Auth/SessionRefreshResponseBody'
|
||||
import { FetchRequestHandler } from './FetchRequestHandler'
|
||||
@@ -21,10 +23,11 @@ import { HttpRequestOptions } from './HttpRequestOptions'
|
||||
export class HttpService implements HttpServiceInterface {
|
||||
private session?: Session | LegacySession
|
||||
private __latencySimulatorMs?: number
|
||||
private __simulateNextSessionRefreshResponseDrop = false
|
||||
private declare host: string
|
||||
loggingEnabled = false
|
||||
|
||||
private inProgressRefreshSessionPromise?: Promise<boolean>
|
||||
private inProgressRefreshSessionPromise?: Promise<Result<HttpResponse<SessionRefreshResponseBody>>>
|
||||
private updateMetaCallback!: (meta: HttpResponseMeta) => void
|
||||
private refreshSessionCallback!: (session: Session) => void
|
||||
|
||||
@@ -34,6 +37,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
private environment: Environment,
|
||||
private appVersion: string,
|
||||
private snjsVersion: string,
|
||||
private apiVersion: ApiVersion,
|
||||
private logger: LoggerInterface,
|
||||
) {
|
||||
this.requestHandler = new FetchRequestHandler(this.snjsVersion, this.appVersion, this.environment, this.logger)
|
||||
@@ -145,6 +149,10 @@ export class HttpService implements HttpServiceInterface {
|
||||
await sleep(this.__latencySimulatorMs, true)
|
||||
}
|
||||
|
||||
httpRequest.params = httpRequest.params
|
||||
? this.params(httpRequest.params as Record<string | number | symbol, unknown>)
|
||||
: undefined
|
||||
|
||||
const isRefreshRequest = httpRequest.url === joinPaths(this.host, Paths.v1.refreshSession)
|
||||
if (this.inProgressRefreshSessionPromise && !isRefreshRequest) {
|
||||
await this.inProgressRefreshSessionPromise
|
||||
@@ -166,12 +174,19 @@ export class HttpService implements HttpServiceInterface {
|
||||
if (this.inProgressRefreshSessionPromise) {
|
||||
await this.inProgressRefreshSessionPromise
|
||||
} else {
|
||||
this.inProgressRefreshSessionPromise = this.refreshSession()
|
||||
const isSessionRefreshed = await this.inProgressRefreshSessionPromise
|
||||
this.inProgressRefreshSessionPromise = undefined
|
||||
const hasSessionTokenRenewedInBetweenOurRequest = httpRequest.authentication !== this.getSessionAccessToken()
|
||||
if (!hasSessionTokenRenewedInBetweenOurRequest) {
|
||||
this.inProgressRefreshSessionPromise = this.refreshSession()
|
||||
const isSessionRefreshedResultOrError = await this.inProgressRefreshSessionPromise
|
||||
let isSessionRefreshed = false
|
||||
if (!isSessionRefreshedResultOrError.isFailed()) {
|
||||
isSessionRefreshed = !isErrorResponse(isSessionRefreshedResultOrError.getValue())
|
||||
}
|
||||
this.inProgressRefreshSessionPromise = undefined
|
||||
|
||||
if (!isSessionRefreshed) {
|
||||
return response
|
||||
if (!isSessionRefreshed) {
|
||||
return response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,13 +198,13 @@ export class HttpService implements HttpServiceInterface {
|
||||
return response
|
||||
}
|
||||
|
||||
async refreshSession(): Promise<boolean> {
|
||||
async refreshSession(): Promise<Result<HttpResponse<SessionRefreshResponseBody>>> {
|
||||
if (!this.session) {
|
||||
return false
|
||||
return Result.fail('No session to refresh')
|
||||
}
|
||||
|
||||
if (this.session instanceof LegacySession) {
|
||||
return false
|
||||
return Result.fail('Cannot refresh legacy session')
|
||||
}
|
||||
|
||||
const response = await this.post<SessionRefreshResponseBody>(Paths.v1.refreshSession, {
|
||||
@@ -197,8 +212,13 @@ export class HttpService implements HttpServiceInterface {
|
||||
refresh_token: this.session.refreshToken.value,
|
||||
})
|
||||
|
||||
if (this.__simulateNextSessionRefreshResponseDrop) {
|
||||
this.__simulateNextSessionRefreshResponseDrop = false
|
||||
return Result.fail('Simulating a dropped response')
|
||||
}
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return false
|
||||
return Result.ok(response)
|
||||
}
|
||||
|
||||
if (response.meta) {
|
||||
@@ -210,7 +230,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
response.data.session.access_expiration,
|
||||
)
|
||||
if (accessTokenOrError.isFailed()) {
|
||||
return false
|
||||
return Result.fail(accessTokenOrError.getError())
|
||||
}
|
||||
|
||||
const accessToken = accessTokenOrError.getValue()
|
||||
@@ -220,20 +240,31 @@ export class HttpService implements HttpServiceInterface {
|
||||
response.data.session.refresh_expiration,
|
||||
)
|
||||
if (refreshTokenOrError.isFailed()) {
|
||||
return false
|
||||
return Result.fail(refreshTokenOrError.getError())
|
||||
}
|
||||
|
||||
const refreshToken = refreshTokenOrError.getValue()
|
||||
|
||||
const sessionOrError = Session.create(accessToken, refreshToken, response.data.session.readonly_access)
|
||||
if (sessionOrError.isFailed()) {
|
||||
return false
|
||||
return Result.fail(sessionOrError.getError())
|
||||
}
|
||||
|
||||
this.setSession(sessionOrError.getValue())
|
||||
|
||||
this.refreshSessionCallback(this.session)
|
||||
|
||||
return true
|
||||
return Result.ok(response)
|
||||
}
|
||||
|
||||
private params(inParams: Record<string | number | symbol, unknown>): HttpRequestParams {
|
||||
const params = {
|
||||
...inParams,
|
||||
...{
|
||||
[ApiEndpointParam.ApiVersion]: this.apiVersion,
|
||||
},
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { LegacySession, Session } from '@standardnotes/domain-core'
|
||||
import { LegacySession, Result, Session } from '@standardnotes/domain-core'
|
||||
import { HttpRequest, HttpRequestParams, HttpResponse, HttpResponseMeta } from '@standardnotes/responses'
|
||||
|
||||
import { HttpRequestOptions } from './HttpRequestOptions'
|
||||
import { SessionRefreshResponseBody } from '../Response'
|
||||
|
||||
export interface HttpServiceInterface {
|
||||
setHost(host: string): void
|
||||
@@ -16,7 +17,7 @@ export interface HttpServiceInterface {
|
||||
runHttp<T>(httpRequest: HttpRequest): Promise<HttpResponse<T>>
|
||||
|
||||
setSession(session: Session | LegacySession): void
|
||||
refreshSession(): Promise<boolean>
|
||||
refreshSession(): Promise<Result<HttpResponse<SessionRefreshResponseBody>>>
|
||||
setCallbacks(
|
||||
updateMetaCallback: (meta: HttpResponseMeta) => void,
|
||||
refreshSessionCallback: (session: Session) => void,
|
||||
|
||||
@@ -4,4 +4,5 @@ export interface SignInWithRecoveryCodesRequestParams {
|
||||
password: string
|
||||
code_verifier: string
|
||||
recovery_codes: string
|
||||
hvm_token?: string
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@ export type UserRegistrationRequestParams = AnyKeyParamsContent & {
|
||||
[additionalParam: string]: unknown
|
||||
password: string
|
||||
email: string
|
||||
hvm_token?: string
|
||||
ephemeral: boolean
|
||||
}
|
||||
|
||||
@@ -3,6 +3,114 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.450](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.449](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.448](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.447](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.446](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.445](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.444](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.443](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.442](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.441](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.440](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.439](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.438](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.437](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.436](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.435](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.434](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.433](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.432](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.431](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.430](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.429](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.428](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.427](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.426](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.425](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.424](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.423](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/clipper",
|
||||
"description": "Web clipper browser extension for Standard Notes",
|
||||
"version": "1.1.423",
|
||||
"version": "1.1.450",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
|
||||
|
||||
@@ -3,6 +3,114 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.110.52](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.51](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.50](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.45](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.44](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.43](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.42](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.41](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.40](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.39](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.38](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.37](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.36](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.30](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.27](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.26](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.25](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.110.25",
|
||||
"version": "3.110.52",
|
||||
"license": "AGPL-3.0",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.21.105](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.104](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.103](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.102](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.21.102",
|
||||
"version": "1.21.105",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.61.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/features
|
||||
|
||||
## [1.61.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/features
|
||||
|
||||
## [1.61.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-11-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/features",
|
||||
"version": "1.61.1",
|
||||
"version": "1.61.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -28,6 +28,7 @@ export class NativeFeatureIdentifier extends ValueObject<NativeFeatureIdentifier
|
||||
MidnightTheme: 'org.standardnotes.theme-midnight',
|
||||
SolarizedDarkTheme: 'org.standardnotes.theme-solarized-dark',
|
||||
TitaniumTheme: 'org.standardnotes.theme-titanium',
|
||||
ProtonTheme: 'com.standardnotes.theme-proton',
|
||||
|
||||
PlainEditor: 'com.standardnotes.plain-text',
|
||||
SuperEditor: 'com.standardnotes.super-editor',
|
||||
|
||||
@@ -97,5 +97,18 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
no_mobile: true,
|
||||
})
|
||||
|
||||
return [midnight, futura, solarizedDark, autobiography, dark, titanium, dynamic]
|
||||
const proton: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Carbon',
|
||||
identifier: NativeFeatureIdentifier.TYPES.ProtonTheme,
|
||||
permission_name: PermissionName.ProtonTheme,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#16141c',
|
||||
foreground_color: '#ffffff',
|
||||
border_color: '#4a4658',
|
||||
},
|
||||
})
|
||||
|
||||
return [midnight, futura, solarizedDark, autobiography, dark, proton, titanium, dynamic]
|
||||
}
|
||||
|
||||
@@ -40,4 +40,5 @@ export enum PermissionName {
|
||||
Clipper = 'app:clipper',
|
||||
Vaults = 'app:vaults',
|
||||
SharedVaults = 'server:shared-vaults',
|
||||
ProtonTheme = 'theme:proton',
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.120](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.119](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.118](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.117](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.28.117",
|
||||
"version": "1.28.120",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.20.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.20.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.20.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.20.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.20.2",
|
||||
"version": "1.20.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,118 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.58.109](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.108](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.107](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.106](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.105](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed super note "Table of contents" not working on mobile ([73eba38](https://github.com/standardnotes/app/commit/73eba38c1444e85839d771fb297e3035eabd99c8))
|
||||
|
||||
## [3.58.104](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.103](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.102](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.101](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.100](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.99](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.98](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.97](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.96](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.95](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.89](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.88](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use API v0 on iOS ([#2858](https://github.com/standardnotes/app/issues/2858)) [skip e2e] ([3b2f761](https://github.com/standardnotes/app/commit/3b2f76166126a5b11f35b64aacefa37618622c3d))
|
||||
|
||||
## [3.58.87](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.86](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.85](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.84](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.83](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.82](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
@@ -158,7 +158,7 @@ platform :android do
|
||||
|
||||
desc 'Deploy production app'
|
||||
lane :prod do
|
||||
version = 3_002_000 + ENV['BUILD_NUMBER'].to_i
|
||||
version = 3_004_000 + ENV['BUILD_NUMBER'].to_i
|
||||
deploy_android 'prod', version
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.58.82",
|
||||
"version": "3.58.109",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.55.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.55.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.55.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
# [1.55.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-17)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.55.0",
|
||||
"version": "1.55.3",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,114 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.745](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.744](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.743](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.742](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.741](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.740](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.739](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.738](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.737](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.736](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.735](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.734](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.733](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.732](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.731](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.730](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.729](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.728](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.727](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.726](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.725](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.724](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.723](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.722](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.721](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.720](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.719](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.718](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.4.718",
|
||||
"version": "1.4.745",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.13.56](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.13.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.13.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.13.53](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-11-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.13.53",
|
||||
"version": "1.13.56",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export type MetaEndpointResponse = {
|
||||
captchaUIUrl: string | null
|
||||
}
|
||||
@@ -26,6 +26,30 @@ export function isErrorResponse<T>(response: HttpResponse<T>): response is HttpE
|
||||
return (response.data as HttpErrorResponseBody)?.error != undefined || response.status >= 400
|
||||
}
|
||||
|
||||
export function getCaptchaHeader<T>(response: HttpResponse<T>) {
|
||||
const captchaHeader = response.headers?.get('x-captcha-required')
|
||||
if (captchaHeader) {
|
||||
return captchaHeader
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getErrorMessageFromErrorResponseBody(data: HttpErrorResponseBody, defaultMessage?: string): string {
|
||||
let errorMessage = defaultMessage || 'Unknown error'
|
||||
if (
|
||||
data &&
|
||||
typeof data === 'object' &&
|
||||
'error' in data &&
|
||||
data.error &&
|
||||
typeof data.error === 'object' &&
|
||||
'message' in data.error
|
||||
) {
|
||||
errorMessage = data.error.message as string
|
||||
}
|
||||
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
export function getErrorFromErrorResponse(response: HttpErrorResponse): HttpError {
|
||||
const embeddedError = response.data.error
|
||||
if (embeddedError) {
|
||||
|
||||
@@ -13,6 +13,7 @@ export * from './Auth/SignInData'
|
||||
export * from './Auth/SignInResponse'
|
||||
export * from './Auth/SignOutResponse'
|
||||
export * from './Auth/User'
|
||||
export * from './Auth/MetaEndpointResponse'
|
||||
|
||||
/** Temps are awaiting final publish state on server repo */
|
||||
export * from './Temp/SharedVaultMoveType'
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.70.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.70.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.70.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.70.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue with system color scheme not being applied correctly on start ([7967dde](https://github.com/standardnotes/app/commit/7967ddead790d89478554cd6a96429fd06958590))
|
||||
|
||||
## [1.70.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.70.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use API v0 on iOS ([#2858](https://github.com/standardnotes/app/issues/2858)) [skip e2e] ([3b2f761](https://github.com/standardnotes/app/commit/3b2f76166126a5b11f35b64aacefa37618622c3d))
|
||||
|
||||
## [1.70.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.70.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.70.1",
|
||||
"version": "1.70.8",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ApiVersion } from '@standardnotes/api'
|
||||
import { Environment, Platform, ApplicationIdentifier } from '@standardnotes/models'
|
||||
import { AlertService, DeviceInterface } from '@standardnotes/services'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
@@ -39,4 +40,6 @@ export interface RequiredApplicationOptions {
|
||||
* Version of client application.
|
||||
*/
|
||||
appVersion: string
|
||||
|
||||
apiVersion: ApiVersion
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ export interface AuthClientInterface {
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
hvmToken?: string
|
||||
}): Promise<
|
||||
| {
|
||||
success: true
|
||||
keyParams: AnyKeyParamsContent
|
||||
session: SessionBody
|
||||
user: {
|
||||
@@ -23,6 +25,9 @@ export interface AuthClientInterface {
|
||||
protocolVersion: string
|
||||
}
|
||||
}
|
||||
| false
|
||||
| {
|
||||
success: false
|
||||
captchaURL: string
|
||||
}
|
||||
>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AuthApiServiceInterface } from '@standardnotes/api'
|
||||
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||
import { isErrorResponse, SessionBody } from '@standardnotes/responses'
|
||||
import { isErrorResponse, getCaptchaHeader } from '@standardnotes/responses'
|
||||
|
||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||
import { AbstractService } from '../Service/AbstractService'
|
||||
@@ -45,37 +45,39 @@ export class AuthManager extends AbstractService implements AuthClientInterface
|
||||
}
|
||||
}
|
||||
|
||||
async signInWithRecoveryCodes(dto: {
|
||||
username: string
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
}): Promise<
|
||||
| {
|
||||
keyParams: AnyKeyParamsContent
|
||||
session: SessionBody
|
||||
user: {
|
||||
uuid: string
|
||||
email: string
|
||||
protocolVersion: string
|
||||
}
|
||||
}
|
||||
| false
|
||||
> {
|
||||
async signInWithRecoveryCodes(
|
||||
dto: Parameters<AuthClientInterface['signInWithRecoveryCodes']>[0],
|
||||
): ReturnType<AuthClientInterface['signInWithRecoveryCodes']> {
|
||||
try {
|
||||
const result = await this.authApiService.signInWithRecoveryCodes(dto)
|
||||
|
||||
const captchaURL = getCaptchaHeader(result)
|
||||
|
||||
if (captchaURL) {
|
||||
return {
|
||||
success: false,
|
||||
captchaURL,
|
||||
}
|
||||
}
|
||||
|
||||
if (isErrorResponse(result)) {
|
||||
return false
|
||||
return {
|
||||
success: false,
|
||||
captchaURL: '',
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
keyParams: result.data.key_params as AnyKeyParamsContent,
|
||||
session: result.data.session,
|
||||
user: result.data.user,
|
||||
}
|
||||
} catch (error) {
|
||||
return false
|
||||
return {
|
||||
success: false,
|
||||
captchaURL: '',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ export interface ComponentManagerInterface {
|
||||
getDefaultEditorIdentifier(currentTag?: SNTag): string
|
||||
|
||||
isThemeActive(theme: UIFeature<ThemeFeatureDescription>): boolean
|
||||
toggleTheme(theme: UIFeature<ThemeFeatureDescription>): Promise<void>
|
||||
toggleTheme(theme: UIFeature<ThemeFeatureDescription>, skipEntitlementCheck?: boolean): Promise<void>
|
||||
toggleOtherNonLayerableThemes(uiFeature: UIFeature<ThemeFeatureDescription>): void
|
||||
getActiveThemes(): UIFeature<ThemeFeatureDescription>[]
|
||||
getActiveThemesIdentifiers(): { features: NativeFeatureIdentifier[]; uuids: Uuid[] }
|
||||
|
||||
|
||||
@@ -30,13 +30,14 @@ export interface SessionsClientInterface {
|
||||
revokeAllOtherSessions(): Promise<void>
|
||||
|
||||
isCurrentSessionReadOnly(): boolean | undefined
|
||||
register(email: string, password: string, ephemeral: boolean): Promise<UserRegistrationResponseBody>
|
||||
register(email: string, password: string, hvmToken: string, ephemeral: boolean): Promise<UserRegistrationResponseBody>
|
||||
signIn(
|
||||
email: string,
|
||||
password: string,
|
||||
strict: boolean,
|
||||
ephemeral: boolean,
|
||||
minAllowedVersion?: ProtocolVersion,
|
||||
hvmToken?: string,
|
||||
): Promise<SessionManagerResponse>
|
||||
bypassChecksAndSignInWithRootKey(
|
||||
email: string,
|
||||
|
||||
@@ -142,6 +142,7 @@ export class UserService
|
||||
public async register(
|
||||
email: string,
|
||||
password: string,
|
||||
hvmToken: string,
|
||||
ephemeral = false,
|
||||
mergeLocal = true,
|
||||
): Promise<UserRegistrationResponseBody> {
|
||||
@@ -157,7 +158,7 @@ export class UserService
|
||||
|
||||
try {
|
||||
this.lockSyncing()
|
||||
const response = await this.sessions.register(email, password, ephemeral)
|
||||
const response = await this.sessions.register(email, password, hvmToken, ephemeral)
|
||||
|
||||
await this.notifyEventSync(AccountEvent.SignedInOrRegistered, {
|
||||
payload: {
|
||||
@@ -190,6 +191,7 @@ export class UserService
|
||||
ephemeral = false,
|
||||
mergeLocal = true,
|
||||
awaitSync = false,
|
||||
hvmToken?: string,
|
||||
): Promise<HttpResponse<SignInResponse>> {
|
||||
if (this.encryption.hasAccount()) {
|
||||
throw Error('Tried to sign in when an account already exists.')
|
||||
@@ -205,7 +207,7 @@ export class UserService
|
||||
/** Prevent a timed sync from occuring while signing in. */
|
||||
this.lockSyncing()
|
||||
|
||||
const { response } = await this.sessions.signIn(email, password, strict, ephemeral)
|
||||
const { response } = await this.sessions.signIn(email, password, strict, ephemeral, undefined, hvmToken)
|
||||
|
||||
if (!isErrorResponse(response)) {
|
||||
const notifyingFunction = awaitSync ? this.notifyEventSync.bind(this) : this.notifyEvent.bind(this)
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface UserServiceInterface extends AbstractService<AccountEvent, Acco
|
||||
register(
|
||||
email: string,
|
||||
password: string,
|
||||
hvmToken: string,
|
||||
ephemeral: boolean,
|
||||
mergeLocal: boolean,
|
||||
): Promise<UserRegistrationResponseBody>
|
||||
@@ -31,6 +32,7 @@ export interface UserServiceInterface extends AbstractService<AccountEvent, Acco
|
||||
ephemeral: boolean,
|
||||
mergeLocal: boolean,
|
||||
awaitSync: boolean,
|
||||
hvmToken?: string,
|
||||
): Promise<HttpResponse<SignInResponse>>
|
||||
deleteAccount(): Promise<{
|
||||
error: boolean
|
||||
|
||||
@@ -203,7 +203,6 @@ export * from './User/SignedInOrRegisteredEventPayload'
|
||||
export * from './User/SignedOutEventPayload'
|
||||
export * from './User/UserService'
|
||||
export * from './User/UserServiceInterface'
|
||||
export * from './User/UserServiceInterface'
|
||||
export * from './UserEvent/NotificationService'
|
||||
export * from './UserEvent/NotificationServiceEvent'
|
||||
export * from './Vault/UseCase/AuthorizeVaultDeletion'
|
||||
|
||||
@@ -3,6 +3,58 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.208.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue with system color scheme not being applied correctly on start ([7967dde](https://github.com/standardnotes/app/commit/7967ddead790d89478554cd6a96429fd06958590))
|
||||
|
||||
## [2.208.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use API v0 on iOS ([#2858](https://github.com/standardnotes/app/issues/2858)) [skip e2e] ([3b2f761](https://github.com/standardnotes/app/commit/3b2f76166126a5b11f35b64aacefa37618622c3d))
|
||||
|
||||
## [2.208.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.208.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
@@ -3,22 +3,10 @@
|
||||
/* Used for running mocha tests */
|
||||
const connect = require('connect')
|
||||
const serveStatic = require('serve-static')
|
||||
const fs = require('fs')
|
||||
|
||||
const isDev = process.argv[2] === '--dev'
|
||||
const port = isDev ? 9002 : 9001
|
||||
|
||||
const snCryptoDistFilePath = `${__dirname}/../sncrypto-web/dist/sncrypto-web.js`
|
||||
if (!fs.existsSync(snCryptoDistFilePath)) {
|
||||
console.error(
|
||||
`Could not find sncrypto dist file under: ${snCryptoDistFilePath}. Please consider building the project first`,
|
||||
)
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
fs.copyFileSync(snCryptoDistFilePath, `${__dirname}/mocha/vendor/sncrypto-web.js`)
|
||||
|
||||
connect()
|
||||
.use(serveStatic(__dirname))
|
||||
.listen(port, () => {
|
||||
|
||||
@@ -98,6 +98,7 @@ import {
|
||||
SignInResponse,
|
||||
ClientDisplayableError,
|
||||
SessionListEntry,
|
||||
MetaEndpointResponse,
|
||||
} from '@standardnotes/responses'
|
||||
import {
|
||||
SyncService,
|
||||
@@ -117,7 +118,7 @@ import {
|
||||
LoggerInterface,
|
||||
canBlockDeinit,
|
||||
} from '@standardnotes/utils'
|
||||
import { UuidString, ApplicationEventPayload } from '../Types'
|
||||
import { UuidString } from '../Types'
|
||||
import { applicationEventForSyncEvent } from '@Lib/Application/Event'
|
||||
import { BackupServiceInterface, FilesClientInterface } from '@standardnotes/files'
|
||||
import { ComputePrivateUsername } from '@standardnotes/encryption'
|
||||
@@ -206,6 +207,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
'identifier',
|
||||
'defaultHost',
|
||||
'appVersion',
|
||||
'apiVersion',
|
||||
]
|
||||
|
||||
for (const optionName of requiredOptions) {
|
||||
@@ -274,12 +276,12 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
}),
|
||||
)
|
||||
|
||||
const syncEventCallback = async (eventName: SyncEvent) => {
|
||||
const syncEventCallback = async (eventName: SyncEvent, data?: unknown) => {
|
||||
const appEvent = applicationEventForSyncEvent(eventName)
|
||||
if (appEvent) {
|
||||
await encryptionService.onSyncEvent(eventName)
|
||||
|
||||
await this.notifyEvent(appEvent)
|
||||
await this.notifyEvent(appEvent, data)
|
||||
|
||||
if (appEvent === ApplicationEvent.CompletedFullSync) {
|
||||
if (!this.handledFullSyncStage) {
|
||||
@@ -534,7 +536,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
return this.addEventObserver(filteredCallback, event)
|
||||
}
|
||||
|
||||
private async notifyEvent(event: ApplicationEvent, data?: ApplicationEventPayload) {
|
||||
private async notifyEvent(event: ApplicationEvent, data?: unknown) {
|
||||
if (event === ApplicationEvent.Started) {
|
||||
this.onStart()
|
||||
} else if (event === ApplicationEvent.Launched) {
|
||||
@@ -767,10 +769,11 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
public async register(
|
||||
email: string,
|
||||
password: string,
|
||||
hvmToken: string,
|
||||
ephemeral = false,
|
||||
mergeLocal = true,
|
||||
): Promise<UserRegistrationResponseBody> {
|
||||
return this.user.register(email, password, ephemeral, mergeLocal)
|
||||
return this.user.register(email, password, hvmToken, ephemeral, mergeLocal)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -784,8 +787,13 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
ephemeral = false,
|
||||
mergeLocal = true,
|
||||
awaitSync = false,
|
||||
hvmToken?: string,
|
||||
): Promise<HttpResponse<SignInResponse>> {
|
||||
return this.user.signIn(email, password, strict, ephemeral, mergeLocal, awaitSync)
|
||||
return this.user.signIn(email, password, strict, ephemeral, mergeLocal, awaitSync, hvmToken)
|
||||
}
|
||||
|
||||
public async getCaptchaUrl(): Promise<HttpResponse<MetaEndpointResponse>> {
|
||||
return this.legacyApi.getCaptchaUrl()
|
||||
}
|
||||
|
||||
public async changeEmail(
|
||||
|
||||
@@ -1090,7 +1090,7 @@ export class Dependencies {
|
||||
})
|
||||
|
||||
this.factory.set(TYPES.AuthApiService, () => {
|
||||
return new AuthApiService(this.get<AuthServer>(TYPES.AuthServer))
|
||||
return new AuthApiService(this.get<AuthServer>(TYPES.AuthServer), this.options.apiVersion)
|
||||
})
|
||||
|
||||
this.factory.set(TYPES.AuthManager, () => {
|
||||
@@ -1432,13 +1432,14 @@ export class Dependencies {
|
||||
})
|
||||
|
||||
this.factory.set(TYPES.SubscriptionApiService, () => {
|
||||
return new SubscriptionApiService(this.get<SubscriptionServer>(TYPES.SubscriptionServer))
|
||||
return new SubscriptionApiService(this.get<SubscriptionServer>(TYPES.SubscriptionServer), this.options.apiVersion)
|
||||
})
|
||||
|
||||
this.factory.set(TYPES.UserApiService, () => {
|
||||
return new UserApiService(
|
||||
this.get<UserServer>(TYPES.UserServer),
|
||||
this.get<UserRequestServer>(TYPES.UserRequestServer),
|
||||
this.options.apiVersion,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1542,6 +1543,7 @@ export class Dependencies {
|
||||
this.options.environment,
|
||||
this.options.appVersion,
|
||||
SnjsVersion,
|
||||
this.options.apiVersion,
|
||||
this.get<Logger>(TYPES.Logger),
|
||||
)
|
||||
})
|
||||
|
||||
+3
-1
@@ -166,7 +166,9 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
})
|
||||
|
||||
it('should fail if the sign in with recovery code fails', async () => {
|
||||
authManager.signInWithRecoveryCodes = jest.fn().mockReturnValue(false)
|
||||
authManager.signInWithRecoveryCodes = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
})
|
||||
|
||||
const useCase = createUseCase()
|
||||
const result = await useCase.execute({
|
||||
|
||||
+10
-1
@@ -68,9 +68,18 @@ export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
|
||||
recoveryCodes: dto.recoveryCodes,
|
||||
username: dto.username,
|
||||
password: rootKey.serverPassword as string,
|
||||
hvmToken: dto.hvmToken,
|
||||
})
|
||||
|
||||
if (signInResult === false) {
|
||||
if (signInResult.success === false) {
|
||||
if (signInResult.captchaURL) {
|
||||
return Result.fail(
|
||||
JSON.stringify({
|
||||
captchaURL: signInResult.captchaURL,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return Result.fail('Could not sign in with recovery code')
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ export interface SignInWithRecoveryCodesDTO {
|
||||
recoveryCodes: string
|
||||
username: string
|
||||
password: string
|
||||
hvmToken?: string
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import {
|
||||
isErrorResponse,
|
||||
MoveFileResponse,
|
||||
ValetTokenOperation,
|
||||
MetaEndpointResponse,
|
||||
} from '@standardnotes/responses'
|
||||
import { LegacySession, MapperInterface, Session, SessionToken } from '@standardnotes/domain-core'
|
||||
import { HttpServiceInterface } from '@standardnotes/api'
|
||||
@@ -81,7 +82,7 @@ import { Strings } from '@Lib/Strings'
|
||||
import { AnyFeatureDescription } from '@standardnotes/features'
|
||||
|
||||
/** Legacy api version field to be specified in params when calling v0 APIs. */
|
||||
const V0_API_VERSION = '20200115'
|
||||
const V0_API_VERSION = '20240226'
|
||||
|
||||
type InvalidSessionObserver = (revoked: boolean) => void
|
||||
|
||||
@@ -290,6 +291,7 @@ export class LegacyApiService
|
||||
email: string
|
||||
serverPassword: string
|
||||
ephemeral: boolean
|
||||
hvmToken?: string
|
||||
}): Promise<HttpResponse<SignInResponse>> {
|
||||
if (this.authenticating) {
|
||||
return this.createErrorResponse(API_MESSAGE_LOGIN_IN_PROGRESS, HttpStatusCode.BadRequest)
|
||||
@@ -301,6 +303,7 @@ export class LegacyApiService
|
||||
password: dto.serverPassword,
|
||||
ephemeral: dto.ephemeral,
|
||||
code_verifier: this.inMemoryStore.getValue(StorageKey.CodeVerifier) as string,
|
||||
hvm_token: dto.hvmToken,
|
||||
})
|
||||
|
||||
const response = await this.request<SignInResponse>({
|
||||
@@ -408,7 +411,12 @@ export class LegacyApiService
|
||||
}
|
||||
}
|
||||
|
||||
async refreshSession(): Promise<HttpResponse<SessionRenewalResponse>> {
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* This function should be replaced with @standardnotes/api's `HttpService::refreshSession` function.
|
||||
*/
|
||||
async deprecatedRefreshSessionOnlyUsedInE2eTests(): Promise<HttpResponse<SessionRenewalResponse>> {
|
||||
const preprocessingError = this.preprocessingError()
|
||||
if (preprocessingError) {
|
||||
return preprocessingError
|
||||
@@ -588,6 +596,26 @@ export class LegacyApiService
|
||||
})
|
||||
}
|
||||
|
||||
async updateSubscriptionSetting(
|
||||
userUuid: UuidString,
|
||||
settingName: string,
|
||||
settingValue: string | null,
|
||||
sensitive: boolean,
|
||||
): Promise<HttpResponse<UpdateSettingResponse>> {
|
||||
const params = {
|
||||
name: settingName,
|
||||
value: settingValue,
|
||||
sensitive: sensitive,
|
||||
}
|
||||
return this.tokenRefreshableRequest<UpdateSettingResponse>({
|
||||
verb: HttpVerb.Put,
|
||||
url: joinPaths(this.host, Paths.v1.subscriptionSettings(userUuid)),
|
||||
authentication: this.getSessionAccessToken(),
|
||||
fallbackErrorMessage: API_MESSAGE_FAILED_UPDATE_SETTINGS,
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async deleteSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<DeleteSettingResponse>> {
|
||||
return this.tokenRefreshableRequest<DeleteSettingResponse>({
|
||||
verb: HttpVerb.Delete,
|
||||
@@ -933,4 +961,9 @@ export class LegacyApiService
|
||||
|
||||
return this.session.accessToken
|
||||
}
|
||||
|
||||
public getCaptchaUrl() {
|
||||
const response = this.httpService.get<MetaEndpointResponse>(Paths.v1.meta)
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ const SettingsPaths = {
|
||||
setting: (userUuid: string, settingName: string) => `/v1/users/${userUuid}/settings/${settingName}`,
|
||||
subscriptionSetting: (userUuid: string, settingName: string) =>
|
||||
`/v1/users/${userUuid}/subscription-settings/${settingName}`,
|
||||
subscriptionSettings: (userUuid: string) => `/v1/users/${userUuid}/subscription-settings`,
|
||||
}
|
||||
|
||||
const SubscriptionPaths = {
|
||||
@@ -69,6 +70,7 @@ export const Paths = {
|
||||
...SettingsPaths,
|
||||
...SubscriptionPaths,
|
||||
...UserPaths,
|
||||
meta: '/v1/meta',
|
||||
},
|
||||
v2: {
|
||||
...UserPathsV2,
|
||||
|
||||
@@ -390,7 +390,20 @@ export class ComponentManager
|
||||
return this.viewers.find((viewer) => viewer.sessionKey === key)
|
||||
}
|
||||
|
||||
public async toggleTheme(uiFeature: UIFeature<ThemeFeatureDescription>): Promise<void> {
|
||||
public toggleOtherNonLayerableThemes(uiFeature: UIFeature<ThemeFeatureDescription>): void {
|
||||
const activeThemes = this.getActiveThemes()
|
||||
for (const candidate of activeThemes) {
|
||||
if (candidate.featureIdentifier === uiFeature.featureIdentifier) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!candidate.layerable) {
|
||||
this.removeActiveTheme(candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async toggleTheme(uiFeature: UIFeature<ThemeFeatureDescription>, skipEntitlementCheck = false): Promise<void> {
|
||||
this.logger.info('Toggling theme', uiFeature.uniqueIdentifier)
|
||||
|
||||
if (this.isThemeActive(uiFeature)) {
|
||||
@@ -399,7 +412,7 @@ export class ComponentManager
|
||||
}
|
||||
|
||||
const featureStatus = this.features.getFeatureStatus(uiFeature.uniqueIdentifier)
|
||||
if (featureStatus !== FeatureStatus.Entitled) {
|
||||
if (!skipEntitlementCheck && featureStatus !== FeatureStatus.Entitled) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -410,16 +423,7 @@ export class ComponentManager
|
||||
if (!uiFeature.layerable) {
|
||||
await sleep(10)
|
||||
|
||||
const activeThemes = this.getActiveThemes()
|
||||
for (const candidate of activeThemes) {
|
||||
if (candidate.featureIdentifier === uiFeature.featureIdentifier) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!candidate.layerable) {
|
||||
this.removeActiveTheme(candidate)
|
||||
}
|
||||
}
|
||||
this.toggleOtherNonLayerableThemes(uiFeature)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +458,7 @@ export class ComponentManager
|
||||
const features: NativeFeatureIdentifier[] = []
|
||||
const uuids: Uuid[] = []
|
||||
|
||||
const strings = this.preferences.getLocalValue(LocalPrefKey.ActiveThemes, [])
|
||||
const strings = new Set(this.preferences.getLocalValue(LocalPrefKey.ActiveThemes, []))
|
||||
for (const string of strings) {
|
||||
const nativeIdentifier = NativeFeatureIdentifier.create(string)
|
||||
if (!nativeIdentifier.isFailed()) {
|
||||
|
||||
@@ -114,8 +114,10 @@ export class GetFeatureStatusUseCase {
|
||||
}
|
||||
|
||||
private isFreeFeature(featureId: NativeFeatureIdentifier) {
|
||||
return [NativeFeatureIdentifier.TYPES.DarkTheme, NativeFeatureIdentifier.TYPES.PlainEditor].includes(
|
||||
featureId.value,
|
||||
)
|
||||
return [
|
||||
NativeFeatureIdentifier.TYPES.DarkTheme,
|
||||
NativeFeatureIdentifier.TYPES.PlainEditor,
|
||||
NativeFeatureIdentifier.TYPES.ProtonTheme,
|
||||
].includes(featureId.value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +404,12 @@ export class SessionManager
|
||||
return undefined
|
||||
}
|
||||
|
||||
async register(email: string, password: string, ephemeral: boolean): Promise<UserRegistrationResponseBody> {
|
||||
async register(
|
||||
email: string,
|
||||
password: string,
|
||||
hvmToken: string,
|
||||
ephemeral: boolean,
|
||||
): Promise<UserRegistrationResponseBody> {
|
||||
if (password.length < MINIMUM_PASSWORD_LENGTH) {
|
||||
throw new ApiCallError(
|
||||
ErrorMessage.InsufficientPasswordMessage.replace('%LENGTH%', MINIMUM_PASSWORD_LENGTH.toString()),
|
||||
@@ -429,6 +434,7 @@ export class SessionManager
|
||||
const registerResponse = await this.userApiService.register({
|
||||
email,
|
||||
serverPassword,
|
||||
hvmToken,
|
||||
keyParams,
|
||||
ephemeral,
|
||||
})
|
||||
@@ -503,8 +509,9 @@ export class SessionManager
|
||||
strict = false,
|
||||
ephemeral = false,
|
||||
minAllowedVersion?: Common.ProtocolVersion,
|
||||
hvmToken?: string,
|
||||
): Promise<SessionManagerResponse> {
|
||||
const result = await this.performSignIn(email, password, strict, ephemeral, minAllowedVersion)
|
||||
const result = await this.performSignIn(email, password, strict, ephemeral, minAllowedVersion, hvmToken)
|
||||
if (
|
||||
isErrorResponse(result.response) &&
|
||||
getErrorFromErrorResponse(result.response).tag !== ErrorTag.ClientValidationError &&
|
||||
@@ -515,7 +522,7 @@ export class SessionManager
|
||||
/**
|
||||
* Try signing in with trimmed + lowercase version of email
|
||||
*/
|
||||
return this.performSignIn(cleanedEmail, password, strict, ephemeral, minAllowedVersion)
|
||||
return this.performSignIn(cleanedEmail, password, strict, ephemeral, minAllowedVersion, hvmToken)
|
||||
} else {
|
||||
return result
|
||||
}
|
||||
@@ -530,6 +537,7 @@ export class SessionManager
|
||||
strict = false,
|
||||
ephemeral = false,
|
||||
minAllowedVersion?: Common.ProtocolVersion,
|
||||
hvmToken?: string,
|
||||
): Promise<SessionManagerResponse> {
|
||||
const paramsResult = await this.retrieveKeyParams({
|
||||
email,
|
||||
@@ -593,7 +601,7 @@ export class SessionManager
|
||||
}
|
||||
}
|
||||
const rootKey = await this.encryptionService.computeRootKey(password, keyParams)
|
||||
const signInResponse = await this.bypassChecksAndSignInWithRootKey(email, rootKey, ephemeral)
|
||||
const signInResponse = await this.bypassChecksAndSignInWithRootKey(email, rootKey, ephemeral, hvmToken)
|
||||
|
||||
return {
|
||||
response: signInResponse,
|
||||
@@ -604,6 +612,7 @@ export class SessionManager
|
||||
email: string,
|
||||
rootKey: SNRootKey,
|
||||
ephemeral = false,
|
||||
hvmToken?: string,
|
||||
): Promise<HttpResponse<SignInResponse>> {
|
||||
const { wrappingKey, canceled } = await this.challengeService.getWrappingKeyIfApplicable()
|
||||
|
||||
@@ -619,6 +628,7 @@ export class SessionManager
|
||||
email,
|
||||
serverPassword: rootKey.serverPassword as string,
|
||||
ephemeral,
|
||||
hvmToken,
|
||||
})
|
||||
|
||||
if (!signInResponse.data || isErrorResponse(signInResponse)) {
|
||||
@@ -874,7 +884,14 @@ export class SessionManager
|
||||
const willRefreshTokenExpireSoon = refreshTokenExpiration.getTime() - Date.now() < ThirtyMinutes
|
||||
|
||||
if (willAccessTokenExpireSoon || willRefreshTokenExpireSoon) {
|
||||
return this.httpService.refreshSession()
|
||||
const refreshSessionResultOrError = await this.httpService.refreshSession()
|
||||
if (refreshSessionResultOrError.isFailed()) {
|
||||
return false
|
||||
}
|
||||
|
||||
const refreshSessionResult = refreshSessionResultOrError.getValue()
|
||||
|
||||
return isErrorResponse(refreshSessionResult)
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -38,6 +38,10 @@ export class SettingsService extends AbstractService implements SettingsClientIn
|
||||
return this.provider.getSubscriptionSetting(name)
|
||||
}
|
||||
|
||||
async updateSubscriptionSetting(name: SettingName, payload: string, sensitive = false) {
|
||||
return this.provider.updateSubscriptionSetting(name, payload, sensitive)
|
||||
}
|
||||
|
||||
async updateSetting(name: SettingName, payload: string, sensitive = false) {
|
||||
return this.provider.updateSetting(name, payload, sensitive)
|
||||
}
|
||||
|
||||
@@ -77,6 +77,13 @@ export class SettingsGateway {
|
||||
return response?.data?.setting?.value ?? undefined
|
||||
}
|
||||
|
||||
async updateSubscriptionSetting(name: SettingName, payload: string, sensitive: boolean): Promise<void> {
|
||||
const response = await this.settingsApi.updateSubscriptionSetting(this.userUuid, name.value, payload, sensitive)
|
||||
if (isErrorResponse(response)) {
|
||||
throw new Error(getErrorFromErrorResponse(response).message)
|
||||
}
|
||||
}
|
||||
|
||||
async getDoesSensitiveSettingExist(name: SettingName): Promise<boolean> {
|
||||
if (!name.isSensitive()) {
|
||||
throw new Error(`Setting ${name.value} is not sensitive`)
|
||||
|
||||
@@ -2,7 +2,6 @@ import { SettingName } from '@standardnotes/domain-core'
|
||||
import { SettingData } from '@standardnotes/responses'
|
||||
import {
|
||||
MuteSignInEmailsOption,
|
||||
MuteFailedBackupsEmailsOption,
|
||||
EmailBackupFrequency,
|
||||
ListedAuthorSecretsData,
|
||||
LogSessionUserAgentOption,
|
||||
@@ -13,7 +12,6 @@ type SettingType =
|
||||
| EmailBackupFrequency
|
||||
| ListedAuthorSecretsData
|
||||
| LogSessionUserAgentOption
|
||||
| MuteFailedBackupsEmailsOption
|
||||
| MuteSignInEmailsOption
|
||||
| MuteMarketingEmailsOption
|
||||
|
||||
|
||||
@@ -21,5 +21,12 @@ export interface SettingsServerInterface {
|
||||
|
||||
getSubscriptionSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<GetSettingResponse>>
|
||||
|
||||
updateSubscriptionSetting(
|
||||
userUuid: UuidString,
|
||||
settingName: string,
|
||||
settingValue: string,
|
||||
sensitive: boolean,
|
||||
): Promise<HttpResponse<UpdateSettingResponse>>
|
||||
|
||||
deleteSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<DeleteSettingResponse>>
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export function createApplicationWithOptions({ identifier, environment, platform
|
||||
defaultHost: host || Defaults.getDefaultHost(),
|
||||
appVersion: Defaults.getAppVersion(),
|
||||
webSocketUrl: Defaults.getDefaultWebSocketUrl(),
|
||||
apiVersion: ApiVersion.v0,
|
||||
syncCallsThresholdPerMinute,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('server session', function () {
|
||||
password: password,
|
||||
})
|
||||
|
||||
const response = await application.legacyApi.refreshSession()
|
||||
const response = await application.legacyApi.deprecatedRefreshSessionOnlyUsedInE2eTests()
|
||||
|
||||
expect(response.status).to.equal(200)
|
||||
expect(response.data.session.access_token).to.be.a('string')
|
||||
@@ -96,8 +96,21 @@ describe('server session', function () {
|
||||
// After the above sync request is completed, we obtain the session information.
|
||||
const sessionAfterSync = application.legacyApi.getSession()
|
||||
|
||||
/**
|
||||
* Access token and refresh token values in the new API version (20240226) represent the session uuid.
|
||||
* So they should stay the same as they were since we are operating on the same session.
|
||||
*
|
||||
* The actual token values are stored in cookies indexed by the session uuid and are not accessible to the client.
|
||||
*
|
||||
* [E2E][Cookies] When e2e supports the expected behavior, we can uncomment the following lines.
|
||||
*
|
||||
*/
|
||||
// expect(sessionBeforeSync.accessToken.value).to.equal(sessionAfterSync.accessToken.value)
|
||||
// expect(sessionBeforeSync.refreshToken.value).to.equal(sessionAfterSync.refreshToken.value)
|
||||
|
||||
expect(sessionBeforeSync.accessToken.value).to.not.equal(sessionAfterSync.accessToken.value)
|
||||
expect(sessionBeforeSync.refreshToken.value).to.not.equal(sessionAfterSync.refreshToken.value)
|
||||
|
||||
expect(sessionBeforeSync.accessToken.expiresAt).to.be.lessThan(sessionAfterSync.accessToken.expiresAt)
|
||||
// New token should expire in the future.
|
||||
expect(sessionAfterSync.accessToken.expiresAt).to.be.greaterThan(Date.now())
|
||||
@@ -165,7 +178,7 @@ describe('server session', function () {
|
||||
expect(sessionFromStorage.refreshExpiration).to.equal(sessionFromApiService.refreshToken.expiresAt)
|
||||
expect(sessionFromStorage.readonlyAccess).to.equal(sessionFromApiService.isReadOnly())
|
||||
|
||||
await application.legacyApi.refreshSession()
|
||||
await application.legacyApi.deprecatedRefreshSessionOnlyUsedInE2eTests()
|
||||
|
||||
const updatedSessionFromStorage = await getSessionFromStorage(application)
|
||||
const updatedSessionFromApiService = application.legacyApi.getSession()
|
||||
@@ -394,9 +407,15 @@ describe('server session', function () {
|
||||
|
||||
await sleepUntilSessionExpires(application, false)
|
||||
|
||||
const refreshSessionResponse = await application.legacyApi.refreshSession()
|
||||
const refreshSessionResponse = await application.legacyApi.deprecatedRefreshSessionOnlyUsedInE2eTests()
|
||||
|
||||
expect(refreshSessionResponse.status).to.equal(400)
|
||||
/**
|
||||
* [E2E][Cookies] The following expectations are commented out because e2e does not support sending cookies with requests yet.
|
||||
*/
|
||||
// expect(refreshSessionResponse.data.error.tag).to.equal('invalid-parameters')
|
||||
// expect(refreshSessionResponse.data.error.message).to.equal('The provided parameters are not valid.')
|
||||
|
||||
expect(refreshSessionResponse.data.error.tag).to.equal('expired-refresh-token')
|
||||
expect(refreshSessionResponse.data.error.message).to.equal('The refresh token has expired.')
|
||||
|
||||
@@ -411,7 +430,11 @@ describe('server session', function () {
|
||||
expect(syncResponse.data.error.message).to.equal('Invalid login credentials.')
|
||||
}).timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
it('should fail when renewing a session with an invalid refresh token', async function () {
|
||||
/**
|
||||
* This test is skipped due to the fact that tokens reside now in cookies and are not accessible to the client.
|
||||
* Thus it is not possible to tamper with the refresh token.
|
||||
*/
|
||||
it.skip('should fail when renewing a session with an invalid refresh token', async function () {
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: email,
|
||||
@@ -429,7 +452,7 @@ describe('server session', function () {
|
||||
})
|
||||
application.sessions.initializeFromDisk()
|
||||
|
||||
const refreshSessionResponse = await application.legacyApi.refreshSession()
|
||||
const refreshSessionResponse = await application.legacyApi.deprecatedRefreshSessionOnlyUsedInE2eTests()
|
||||
|
||||
expect(refreshSessionResponse.status).to.equal(400)
|
||||
expect(refreshSessionResponse.data.error.tag).to.equal('invalid-refresh-token')
|
||||
@@ -447,7 +470,7 @@ describe('server session', function () {
|
||||
password: password,
|
||||
})
|
||||
|
||||
const refreshPromise = application.legacyApi.refreshSession()
|
||||
const refreshPromise = application.legacyApi.deprecatedRefreshSessionOnlyUsedInE2eTests()
|
||||
const syncResponse = await application.legacyApi.sync([])
|
||||
|
||||
expect(syncResponse.data.error).to.be.ok
|
||||
@@ -458,6 +481,57 @@ describe('server session', function () {
|
||||
await refreshPromise
|
||||
})
|
||||
|
||||
it('should tell the client to refresh the token if one is used during the cooldown period after a refresh', async function () {
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: email,
|
||||
password: password,
|
||||
})
|
||||
|
||||
const mimickApplyingSessionFromTheServerUnsuccessfully = () => {}
|
||||
const originalSetSessionFn = application.http.setSession
|
||||
const originalRefreshSessionCallbackFn = application.http.refreshSessionCallback
|
||||
application.http.setSession = mimickApplyingSessionFromTheServerUnsuccessfully
|
||||
application.http.refreshSessionCallback = mimickApplyingSessionFromTheServerUnsuccessfully
|
||||
|
||||
const refreshResultOrError = await application.http.refreshSession()
|
||||
expect(refreshResultOrError.isFailed()).to.equal(false)
|
||||
|
||||
const refreshResult = refreshResultOrError.getValue()
|
||||
expect(isErrorResponse(refreshResult)).to.equal(false)
|
||||
|
||||
const secondRefreshResultOrErrorWithNotAppliedSession = await application.http.refreshSession()
|
||||
expect(secondRefreshResultOrErrorWithNotAppliedSession.isFailed()).to.equal(false)
|
||||
|
||||
const secondRefreshResultWithNotAppliedSession = secondRefreshResultOrErrorWithNotAppliedSession.getValue()
|
||||
expect(isErrorResponse(secondRefreshResultWithNotAppliedSession)).to.equal(false)
|
||||
|
||||
application.http.setSession = originalSetSessionFn
|
||||
application.http.refreshSessionCallback = originalRefreshSessionCallbackFn
|
||||
})
|
||||
|
||||
it('if session renewal response is dropped, next sync with server should return a 498 and successfully renew the session', async function () {
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: email,
|
||||
password: password,
|
||||
})
|
||||
|
||||
await sleepUntilSessionExpires(application)
|
||||
|
||||
const refreshSpy = sinon.spy(application.http, 'refreshSession')
|
||||
|
||||
/**
|
||||
* With this sync, we expect refreshSession to be called twice, once where the response is dropped,
|
||||
* and the other time where the request succeeds
|
||||
*/
|
||||
application.http.__simulateNextSessionRefreshResponseDrop = true
|
||||
await application.sync.sync(syncOptions)
|
||||
await application.sync.sync(syncOptions)
|
||||
|
||||
expect(refreshSpy.callCount).to.equal(2)
|
||||
})
|
||||
|
||||
it('notes should be synced as expected after refreshing a session', async function () {
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
|
||||
@@ -123,12 +123,12 @@ describe('settings service', function () {
|
||||
true,
|
||||
)
|
||||
await application.settings.updateSetting(
|
||||
SettingName.create(SettingName.NAMES.MuteFailedBackupsEmails).getValue(),
|
||||
MuteFailedBackupsEmailsOption.Muted,
|
||||
SettingName.create(SettingName.NAMES.LogSessionUserAgent).getValue(),
|
||||
LogSessionUserAgentOption.Enabled,
|
||||
)
|
||||
const settings = await application.settings.listSettings()
|
||||
expect(settings.getSettingValue(SettingName.create(SettingName.NAMES.MuteFailedBackupsEmails).getValue())).to.eql(
|
||||
MuteFailedBackupsEmailsOption.Muted,
|
||||
expect(settings.getSettingValue(SettingName.create(SettingName.NAMES.LogSessionUserAgent).getValue())).to.eql(
|
||||
LogSessionUserAgentOption.Enabled,
|
||||
)
|
||||
expect(settings.getSettingValue(SettingName.create(SettingName.NAMES.MfaSecret).getValue())).to.not.be.ok
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<script src="https://unpkg.com/[email protected]/mocha.js"></script>
|
||||
<script src="https://unpkg.com/[email protected]/lib/chai-subset.js"></script>
|
||||
<script src="https://unpkg.com/[email protected]/pkg/sinon.js"></script>
|
||||
<script src="./vendor/sncrypto-web.js"></script>
|
||||
<script src="https://unpkg.com/@standardnotes/[email protected]/dist/sncrypto-web.js"></script>
|
||||
<script src="../dist/snjs.js"></script>
|
||||
|
||||
<script type="module">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.208.6",
|
||||
"version": "2.208.18",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.8.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/styles
|
||||
|
||||
## [1.8.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-10-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/styles
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/styles",
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.2",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -45,3 +45,10 @@
|
||||
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.windows-web,
|
||||
.windows-desktop {
|
||||
.md\:hover\:overflow-y-auto {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.37.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue with system color scheme on mobile ([45ca99c](https://github.com/standardnotes/app/commit/45ca99c627e51b0b6b0b55e211788fa4cb0f1c70))
|
||||
|
||||
## [1.37.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue with system color scheme not being applied correctly on start ([7967dde](https://github.com/standardnotes/app/commit/7967ddead790d89478554cd6a96429fd06958590))
|
||||
|
||||
## [1.37.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.37.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.37.1",
|
||||
"version": "1.37.10",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -27,7 +27,9 @@ const DefaultThemeIdentifier = 'Default'
|
||||
|
||||
export class ThemeManager extends AbstractUIService {
|
||||
private themesActiveInTheUI: ActiveThemeList
|
||||
private lastUseDeviceThemeSettings = false
|
||||
private lastUseDeviceThemeSettings: boolean | undefined
|
||||
private lastAutoLightTheme: string | undefined
|
||||
private lastAutoDarkTheme: string | undefined
|
||||
|
||||
constructor(
|
||||
application: WebApplicationInterface,
|
||||
@@ -89,7 +91,7 @@ export class ThemeManager extends AbstractUIService {
|
||||
break
|
||||
}
|
||||
case ApplicationEvent.FeaturesAvailabilityChanged: {
|
||||
this.handleFeaturesAvailabilityChanged()
|
||||
this.handleFeaturesAvailabilityChanged().catch(console.error)
|
||||
break
|
||||
}
|
||||
case ApplicationEvent.Launched: {
|
||||
@@ -166,15 +168,25 @@ export class ThemeManager extends AbstractUIService {
|
||||
|
||||
this.toggleTranslucentUIColors()
|
||||
|
||||
const useDeviceThemeSettings = this.preferences.getLocalValue(LocalPrefKey.UseSystemColorScheme, false)
|
||||
const useSystemColorScheme = this.preferences.getLocalValue(LocalPrefKey.UseSystemColorScheme, false)
|
||||
const autoLightTheme = this.preferences.getLocalValue(LocalPrefKey.AutoLightThemeIdentifier, DefaultThemeIdentifier)
|
||||
const autoDarkTheme = this.preferences.getLocalValue(
|
||||
LocalPrefKey.AutoDarkThemeIdentifier,
|
||||
NativeFeatureIdentifier.TYPES.DarkTheme,
|
||||
)
|
||||
|
||||
const hasPreferenceChanged = useDeviceThemeSettings !== this.lastUseDeviceThemeSettings
|
||||
const hasPreferenceChanged =
|
||||
useSystemColorScheme !== this.lastUseDeviceThemeSettings ||
|
||||
autoLightTheme !== this.lastAutoLightTheme ||
|
||||
autoDarkTheme !== this.lastAutoDarkTheme
|
||||
|
||||
if (hasPreferenceChanged) {
|
||||
this.lastUseDeviceThemeSettings = useDeviceThemeSettings
|
||||
this.lastUseDeviceThemeSettings = useSystemColorScheme
|
||||
this.lastAutoLightTheme = autoLightTheme
|
||||
this.lastAutoDarkTheme = autoDarkTheme
|
||||
}
|
||||
|
||||
if (hasPreferenceChanged && useDeviceThemeSettings) {
|
||||
if (hasPreferenceChanged && useSystemColorScheme) {
|
||||
let prefersDarkColorScheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
@@ -185,7 +197,7 @@ export class ThemeManager extends AbstractUIService {
|
||||
}
|
||||
}
|
||||
|
||||
private handleFeaturesAvailabilityChanged(): void {
|
||||
private async handleFeaturesAvailabilityChanged() {
|
||||
let hasChange = false
|
||||
|
||||
for (const theme of this.themesActiveInTheUI.asThemes()) {
|
||||
@@ -205,6 +217,15 @@ export class ThemeManager extends AbstractUIService {
|
||||
}
|
||||
}
|
||||
|
||||
const shouldSetThemeAsPerColorScheme = this.preferences.getLocalValue(LocalPrefKey.UseSystemColorScheme, false)
|
||||
if (shouldSetThemeAsPerColorScheme) {
|
||||
let prefersDarkColorScheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
prefersDarkColorScheme = (await this.application.mobileDevice.getColorScheme()) === 'dark'
|
||||
}
|
||||
hasChange = this.setThemeAsPerColorScheme(prefersDarkColorScheme)
|
||||
}
|
||||
|
||||
if (hasChange) {
|
||||
void this.cacheThemeState()
|
||||
}
|
||||
@@ -218,7 +239,9 @@ export class ThemeManager extends AbstractUIService {
|
||||
}
|
||||
}
|
||||
|
||||
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean) {
|
||||
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean): boolean {
|
||||
let didChangeTheme = false
|
||||
|
||||
const preference = prefersDarkColorScheme
|
||||
? LocalPrefKey.AutoDarkThemeIdentifier
|
||||
: LocalPrefKey.AutoLightThemeIdentifier
|
||||
@@ -239,6 +262,7 @@ export class ThemeManager extends AbstractUIService {
|
||||
const toggleActiveTheme = () => {
|
||||
if (activeTheme) {
|
||||
void this.components.toggleTheme(activeTheme)
|
||||
didChangeTheme = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,10 +270,17 @@ export class ThemeManager extends AbstractUIService {
|
||||
toggleActiveTheme()
|
||||
} else {
|
||||
const theme = themes.find((theme) => theme.featureIdentifier === themeIdentifier)
|
||||
if (theme && !this.components.isThemeActive(theme)) {
|
||||
this.components.toggleTheme(theme).catch(console.error)
|
||||
if (theme) {
|
||||
if (!this.components.isThemeActive(theme)) {
|
||||
this.components.toggleTheme(theme, true).catch(console.error)
|
||||
} else {
|
||||
this.components.toggleOtherNonLayerableThemes(theme)
|
||||
}
|
||||
didChangeTheme = true
|
||||
}
|
||||
}
|
||||
|
||||
return didChangeTheme
|
||||
}
|
||||
|
||||
private async activateCachedThemes() {
|
||||
|
||||
@@ -3,6 +3,122 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.192.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed super note "Table of contents" not working on mobile ([73eba38](https://github.com/standardnotes/app/commit/73eba38c1444e85839d771fb297e3035eabd99c8))
|
||||
|
||||
## [3.192.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.192.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: Markdown text is now parsed correctly when pasted" ([bb81c8a](https://github.com/standardnotes/app/commit/bb81c8acfc470df76a70ab74fa8d487216e2d190))
|
||||
|
||||
# [3.192.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue with re-authentication prompts ([6d872cd](https://github.com/standardnotes/app/commit/6d872cd45a504c824d6fa2d3325e1ba2401f3046))
|
||||
|
||||
## [3.191.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue with re-authentication prompts ([#2858](https://github.com/standardnotes/app/issues/2858)) [skip e2e] ([3b2f761](https://github.com/standardnotes/app/commit/3b2f76166126a5b11f35b64aacefa37618622c3d))
|
||||
|
||||
## [3.191.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.191.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
@@ -1,5 +1,314 @@
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"version": "3.192.15",
|
||||
"title": "[3.192.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.14",
|
||||
"title": "[3.192.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-10)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.13",
|
||||
"title": "[3.192.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-08)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.10",
|
||||
"title": "[3.192.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-04)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.9",
|
||||
"title": "[3.192.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-04-01)",
|
||||
"date": null,
|
||||
"body": "### Bug Fixes\n\n* Fixed super note \"Table of contents\" not working on mobile ([73eba38](https://github.com/standardnotes/app/commit/73eba38c1444e85839d771fb297e3035eabd99c8))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Fixed super note \"Table of contents\" not working on mobile (73eba38)"
|
||||
],
|
||||
"Bug Fixes": [
|
||||
"Fixed super note \"Table of contents\" not working on mobile (73eba38)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.8",
|
||||
"title": "[3.192.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-28)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.7",
|
||||
"title": "[3.192.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-27)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.6",
|
||||
"title": "[3.192.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.5",
|
||||
"title": "[3.192.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-26)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.4",
|
||||
"title": "[3.192.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.3",
|
||||
"title": "[3.192.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.2",
|
||||
"title": "[3.192.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-22)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.1",
|
||||
"title": "[3.192.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)",
|
||||
"date": null,
|
||||
"body": "### Reverts\n\n* Revert \"feat: Markdown text is now parsed correctly when pasted\" ([bb81c8a](https://github.com/standardnotes/app/commit/bb81c8acfc470df76a70ab74fa8d487216e2d190))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Revert \"feat: Markdown text is now parsed correctly when pasted\" (bb81c8a)"
|
||||
],
|
||||
"Reverts": [
|
||||
"Revert \"feat: Markdown text is now parsed correctly when pasted\" (bb81c8a)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.192.0",
|
||||
"title": "[3.192.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.24",
|
||||
"title": "[3.191.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-14)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.23",
|
||||
"title": "[3.191.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-13)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.22",
|
||||
"title": "[3.191.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-12)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.21",
|
||||
"title": "[3.191.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)",
|
||||
"date": null,
|
||||
"body": "### Bug Fixes\n\n* Fixed issue with re-authentication prompts ([6d872cd](https://github.com/standardnotes/app/commit/6d872cd45a504c824d6fa2d3325e1ba2401f3046))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Fixed issue with re-authentication prompts (6d872cd)"
|
||||
],
|
||||
"Bug Fixes": [
|
||||
"Fixed issue with re-authentication prompts (6d872cd)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.20",
|
||||
"title": "[3.191.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.19",
|
||||
"title": "[3.191.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-11)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.18",
|
||||
"title": "[3.191.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-08)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.17",
|
||||
"title": "[3.191.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)",
|
||||
"date": null,
|
||||
"body": "### Bug Fixes\n\n* Fixed issue with re-authentication prompts ([#2858](https://github.com/standardnotes/app/issues/2858)) [skip e2e] ([3b2f761](https://github.com/standardnotes/app/commit/3b2f76166126a5b11f35b64aacefa37618622c3d))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Fixed issue with re-authentication prompts (#2858) skip e2e] ([3b2f761)"
|
||||
],
|
||||
"Bug Fixes": [
|
||||
"Fixed issue with re-authentication prompts (#2858) skip e2e] ([3b2f761)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.16",
|
||||
"title": "[3.191.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-07)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.15",
|
||||
"title": "[3.191.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-06)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.14",
|
||||
"title": "[3.191.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.13",
|
||||
"title": "[3.191.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-05)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.12",
|
||||
"title": "[3.191.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.191.11",
|
||||
"title": "[3.191.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-03-01)",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY ./dist /usr/share/nginx/html
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.191.11",
|
||||
"version": "3.192.15",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes",
|
||||
@@ -110,6 +110,10 @@
|
||||
"dependencies": {
|
||||
"@ariakit/react": "^0.3.9",
|
||||
"@lexical/headless": "0.13.1",
|
||||
"@lexical/link": "0.13.1",
|
||||
"@lexical/list": "0.13.1",
|
||||
"@lexical/rich-text": "0.13.1",
|
||||
"@lexical/utils": "0.13.1",
|
||||
"@radix-ui/react-slot": "^1.0.1",
|
||||
"@react-pdf/renderer": "^3.3.2",
|
||||
"comlink": "^4.4.1",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
:root {
|
||||
--background-norm: #16141c;
|
||||
--background-weak: #292733;
|
||||
--background-strong: #3f3b4c;
|
||||
--text-norm: #ffffff;
|
||||
--text-weak: #a7a4b5;
|
||||
--border-norm: #4a4658;
|
||||
--border-weak: #343140;
|
||||
--primary: #8a6eff;
|
||||
--interaction-norm: #6d4aff;
|
||||
|
||||
--sn-stylekit-background-color: var(--background-norm);
|
||||
--sn-stylekit-foreground-color: var(--text-norm);
|
||||
--sn-stylekit-border-color: var(--border-weak);
|
||||
--sn-stylekit-contrast-background-color: var(--background-weak);
|
||||
--sn-stylekit-contrast-foreground-color: var(--text-norm);
|
||||
--sn-stylekit-contrast-border-color: var(--border-norm);
|
||||
--sn-stylekit-secondary-background-color: var(--background-weak);
|
||||
--sn-stylekit-secondary-foreground-color: var(--text-norm);
|
||||
--sn-stylekit-info-color: var(--interaction-norm);
|
||||
--sn-stylekit-info-backdrop-color: #6e4aff0f;
|
||||
--sn-stylekit-passive-color-0: var(--text-weak);
|
||||
--sn-stylekit-passive-color-3: var(--background-strong);
|
||||
--sn-stylekit-passive-color-4: #3f3b4c;
|
||||
--sn-stylekit-passive-color-5: var(--background-weak);
|
||||
|
||||
--navigation-item-selected-background-color: var(--background-strong);
|
||||
|
||||
--sn-stylekit-paragraph-text-color: var(--text-weak);
|
||||
--sn-stylekit-scrollbar-thumb-color: var(--primary);
|
||||
}
|
||||
|
||||
a,
|
||||
.Lexical__link,
|
||||
.Lexical__textCode {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.Collapsible__container,
|
||||
.Lexical__tableCellHeader {
|
||||
border-color: var(--border-norm);
|
||||
}
|
||||
|
||||
.Lexical__quote {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
#blocks-editor hr.selected {
|
||||
outline-color: var(--primary);
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
SNNote,
|
||||
DesktopManagerInterface,
|
||||
FileItem,
|
||||
ApiVersion,
|
||||
} from '@standardnotes/snjs'
|
||||
import { action, computed, makeObservable, observable } from 'mobx'
|
||||
import { startAuthentication, startRegistration } from '@simplewebauthn/browser'
|
||||
@@ -112,6 +113,10 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
defaultHost: defaultSyncServerHost,
|
||||
appVersion: deviceInterface.appVersion,
|
||||
webSocketUrl: webSocketUrl,
|
||||
/**
|
||||
* iOS file:// based origin does not work with production cookies
|
||||
*/
|
||||
apiVersion: platform === Platform.Ios || platform === Platform.Android ? ApiVersion.v0 : ApiVersion.v1,
|
||||
loadBatchSize:
|
||||
deviceInterface.environment === Environment.Mobile ? 250 : ApplicationOptionsDefaults.loadBatchSize,
|
||||
sleepBetweenBatches:
|
||||
|
||||
@@ -16,6 +16,8 @@ import DecoratedPasswordInput from '@/Components/Input/DecoratedPasswordInput'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import IconButton from '@/Components/Button/IconButton'
|
||||
import { useApplication } from '../ApplicationProvider'
|
||||
import { useCaptcha } from '@/Hooks/useCaptcha'
|
||||
import { isErrorResponse } from '@standardnotes/snjs'
|
||||
|
||||
type Props = {
|
||||
setMenuPane: (pane: AccountMenuPane) => void
|
||||
@@ -33,6 +35,39 @@ const ConfirmPassword: FunctionComponent<Props> = ({ setMenuPane, email, passwor
|
||||
const [shouldMergeLocal, setShouldMergeLocal] = useState(true)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const [hvmToken, setHVMToken] = useState('')
|
||||
const [captchaURL, setCaptchaURL] = useState('')
|
||||
|
||||
const register = useCallback(() => {
|
||||
setIsRegistering(true)
|
||||
application
|
||||
.register(email, password, hvmToken, isEphemeral, shouldMergeLocal)
|
||||
.then(() => {
|
||||
application.accountMenuController.closeAccountMenu()
|
||||
application.accountMenuController.setCurrentPane(AccountMenuPane.GeneralMenu)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
setError(err.message)
|
||||
})
|
||||
.finally(() => {
|
||||
setIsRegistering(false)
|
||||
})
|
||||
}, [application, email, hvmToken, isEphemeral, password, shouldMergeLocal])
|
||||
|
||||
const captchaIframe = useCaptcha(captchaURL, (token) => {
|
||||
setHVMToken(token)
|
||||
setCaptchaURL('')
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!hvmToken) {
|
||||
return
|
||||
}
|
||||
|
||||
register()
|
||||
}, [hvmToken, register])
|
||||
|
||||
const passwordInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -51,6 +86,28 @@ const ConfirmPassword: FunctionComponent<Props> = ({ setMenuPane, email, passwor
|
||||
setShouldMergeLocal(!shouldMergeLocal)
|
||||
}, [shouldMergeLocal])
|
||||
|
||||
const checkIfCaptchaRequiredAndRegister = useCallback(() => {
|
||||
application
|
||||
.getCaptchaUrl()
|
||||
.then((response) => {
|
||||
if (isErrorResponse(response)) {
|
||||
throw new Error()
|
||||
}
|
||||
const { captchaUIUrl } = response.data
|
||||
if (captchaUIUrl) {
|
||||
setCaptchaURL(captchaUIUrl)
|
||||
} else {
|
||||
setCaptchaURL('')
|
||||
register()
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
setCaptchaURL('')
|
||||
register()
|
||||
})
|
||||
}, [application, register])
|
||||
|
||||
const handleConfirmFormSubmit: FormEventHandler = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault()
|
||||
@@ -60,28 +117,16 @@ const ConfirmPassword: FunctionComponent<Props> = ({ setMenuPane, email, passwor
|
||||
return
|
||||
}
|
||||
|
||||
if (password === confirmPassword) {
|
||||
setIsRegistering(true)
|
||||
application
|
||||
.register(email, password, isEphemeral, shouldMergeLocal)
|
||||
.then(() => {
|
||||
application.accountMenuController.closeAccountMenu()
|
||||
application.accountMenuController.setCurrentPane(AccountMenuPane.GeneralMenu)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
setError(err.message)
|
||||
})
|
||||
.finally(() => {
|
||||
setIsRegistering(false)
|
||||
})
|
||||
} else {
|
||||
if (password !== confirmPassword) {
|
||||
setError(STRING_NON_MATCHING_PASSWORDS)
|
||||
setConfirmPassword('')
|
||||
passwordInputRef.current?.focus()
|
||||
return
|
||||
}
|
||||
|
||||
checkIfCaptchaRequiredAndRegister()
|
||||
},
|
||||
[application, confirmPassword, email, isEphemeral, password, shouldMergeLocal],
|
||||
[checkIfCaptchaRequiredAndRegister, confirmPassword, password],
|
||||
)
|
||||
|
||||
const handleKeyDown: KeyboardEventHandler = useCallback(
|
||||
@@ -100,35 +145,26 @@ const ConfirmPassword: FunctionComponent<Props> = ({ setMenuPane, email, passwor
|
||||
setMenuPane(AccountMenuPane.Register)
|
||||
}, [setMenuPane])
|
||||
|
||||
return (
|
||||
const confirmPasswordForm = (
|
||||
<>
|
||||
<div className="mb-3 mt-1 flex items-center px-3">
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
title="Go back"
|
||||
className="mr-2 flex p-0 text-neutral"
|
||||
onClick={handleGoBack}
|
||||
focusable={true}
|
||||
disabled={isRegistering}
|
||||
/>
|
||||
<div className="text-base font-bold">Confirm password</div>
|
||||
</div>
|
||||
<div className="mb-3 px-3 text-sm">
|
||||
Because your notes are encrypted using your password,{' '}
|
||||
<span className="text-danger">Standard Notes does not have a password reset option</span>. If you forget your
|
||||
password, you will permanently lose access to your data.
|
||||
</div>
|
||||
<form onSubmit={handleConfirmFormSubmit} className="mb-1 px-3">
|
||||
<DecoratedPasswordInput
|
||||
className={{ container: 'mb-2' }}
|
||||
disabled={isRegistering}
|
||||
left={[<Icon type="password" className="text-neutral" />]}
|
||||
onChange={handlePasswordChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Confirm password"
|
||||
ref={passwordInputRef}
|
||||
value={confirmPassword}
|
||||
/>
|
||||
{!isRegistering && (
|
||||
<DecoratedPasswordInput
|
||||
className={{ container: 'mb-2' }}
|
||||
disabled={isRegistering}
|
||||
left={[<Icon type="password" className="text-neutral" />]}
|
||||
onChange={handlePasswordChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Confirm password"
|
||||
ref={passwordInputRef}
|
||||
value={confirmPassword}
|
||||
/>
|
||||
)}
|
||||
{error ? <div className="my-2 text-danger">{error}</div> : null}
|
||||
<Button
|
||||
primary
|
||||
@@ -157,6 +193,23 @@ const ConfirmPassword: FunctionComponent<Props> = ({ setMenuPane, email, passwor
|
||||
</form>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-3 mt-1 flex items-center px-3">
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
title="Go back"
|
||||
className="mr-2 flex p-0 text-neutral"
|
||||
onClick={handleGoBack}
|
||||
focusable={true}
|
||||
disabled={isRegistering}
|
||||
/>
|
||||
<div className="text-base font-bold">{captchaURL ? 'Human verification' : 'Confirm password'}</div>
|
||||
</div>
|
||||
{captchaURL ? <div className="p-[10px]">{captchaIframe}</div> : confirmPasswordForm}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(ConfirmPassword)
|
||||
|
||||
@@ -10,8 +10,9 @@ import Icon from '@/Components/Icon/Icon'
|
||||
import IconButton from '@/Components/Button/IconButton'
|
||||
import AdvancedOptions from './AdvancedOptions'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import { getErrorFromErrorResponse, isErrorResponse } from '@standardnotes/snjs'
|
||||
import { getErrorFromErrorResponse, isErrorResponse, getCaptchaHeader } from '@standardnotes/snjs'
|
||||
import { useApplication } from '../ApplicationProvider'
|
||||
import { useCaptcha } from '@/Hooks/useCaptcha'
|
||||
|
||||
type Props = {
|
||||
setMenuPane: (pane: AccountMenuPane) => void
|
||||
@@ -34,6 +35,15 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
|
||||
const [isRecoverySignIn, setIsRecoverySignIn] = useState(false)
|
||||
|
||||
const [captchaURL, setCaptchaURL] = useState('')
|
||||
const [showCaptcha, setShowCaptcha] = useState(false)
|
||||
const [hvmToken, setHVMToken] = useState('')
|
||||
const captchaIframe = useCaptcha(captchaURL, (token) => {
|
||||
setHVMToken(token)
|
||||
setShowCaptcha(false)
|
||||
setCaptchaURL('')
|
||||
})
|
||||
|
||||
const emailInputRef = useRef<HTMLInputElement>(null)
|
||||
const passwordInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
@@ -95,8 +105,12 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
passwordInputRef?.current?.blur()
|
||||
|
||||
application
|
||||
.signIn(email, password, isStrictSignin, isEphemeral, shouldMergeLocal)
|
||||
.signIn(email, password, isStrictSignin, isEphemeral, shouldMergeLocal, false, hvmToken)
|
||||
.then((response) => {
|
||||
const captchaURL = getCaptchaHeader(response)
|
||||
if (captchaURL) {
|
||||
setCaptchaURL(captchaURL)
|
||||
}
|
||||
if (isErrorResponse(response)) {
|
||||
throw new Error(getErrorFromErrorResponse(response).message)
|
||||
}
|
||||
@@ -106,12 +120,13 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
console.error(err)
|
||||
setError(err.message ?? err.toString())
|
||||
setPassword('')
|
||||
setHVMToken('')
|
||||
passwordInputRef?.current?.blur()
|
||||
})
|
||||
.finally(() => {
|
||||
setIsSigningIn(false)
|
||||
})
|
||||
}, [application, email, isEphemeral, isStrictSignin, password, shouldMergeLocal])
|
||||
}, [application, email, hvmToken, isEphemeral, isStrictSignin, password, shouldMergeLocal])
|
||||
|
||||
const recoverySignIn = useCallback(() => {
|
||||
setIsSigningIn(true)
|
||||
@@ -123,10 +138,21 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
recoveryCodes,
|
||||
username: email,
|
||||
password: password,
|
||||
hvmToken,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.isFailed()) {
|
||||
throw new Error(result.getError())
|
||||
const error = result.getError()
|
||||
try {
|
||||
const parsed = JSON.parse(error)
|
||||
if (parsed.captchaURL) {
|
||||
setCaptchaURL(parsed.captchaURL)
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
setCaptchaURL('')
|
||||
}
|
||||
throw new Error(error)
|
||||
}
|
||||
application.accountMenuController.closeAccountMenu()
|
||||
})
|
||||
@@ -134,12 +160,13 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
console.error(err)
|
||||
setError(err.message ?? err.toString())
|
||||
setPassword('')
|
||||
setHVMToken('')
|
||||
passwordInputRef?.current?.blur()
|
||||
})
|
||||
.finally(() => {
|
||||
setIsSigningIn(false)
|
||||
})
|
||||
}, [application, email, password, recoveryCodes])
|
||||
}, [application.accountMenuController, application.signInWithRecoveryCodes, email, hvmToken, password, recoveryCodes])
|
||||
|
||||
const onPrivateUsernameChange = useCallback(
|
||||
(newisPrivateUsername: boolean, privateUsernameIdentifier?: string) => {
|
||||
@@ -151,28 +178,37 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
[setEmail],
|
||||
)
|
||||
|
||||
const performSignIn = useCallback(() => {
|
||||
if (!email || email.length === 0) {
|
||||
emailInputRef?.current?.focus()
|
||||
return
|
||||
}
|
||||
|
||||
if (!password || password.length === 0) {
|
||||
passwordInputRef?.current?.focus()
|
||||
return
|
||||
}
|
||||
|
||||
if (isRecoverySignIn) {
|
||||
recoverySignIn()
|
||||
return
|
||||
}
|
||||
|
||||
signIn()
|
||||
}, [email, isRecoverySignIn, password, recoverySignIn, signIn])
|
||||
|
||||
const handleSignInFormSubmit = useCallback(
|
||||
(e: React.SyntheticEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (!email || email.length === 0) {
|
||||
emailInputRef?.current?.focus()
|
||||
if (captchaURL) {
|
||||
setShowCaptcha(true)
|
||||
return
|
||||
}
|
||||
|
||||
if (!password || password.length === 0) {
|
||||
passwordInputRef?.current?.focus()
|
||||
return
|
||||
}
|
||||
|
||||
if (isRecoverySignIn) {
|
||||
recoverySignIn()
|
||||
return
|
||||
}
|
||||
|
||||
signIn()
|
||||
performSignIn()
|
||||
},
|
||||
[email, password, isRecoverySignIn, signIn, recoverySignIn],
|
||||
[captchaURL, performSignIn],
|
||||
)
|
||||
|
||||
const handleKeyDown: KeyboardEventHandler = useCallback(
|
||||
@@ -184,19 +220,16 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
[handleSignInFormSubmit],
|
||||
)
|
||||
|
||||
return (
|
||||
useEffect(() => {
|
||||
if (!hvmToken) {
|
||||
return
|
||||
}
|
||||
|
||||
performSignIn()
|
||||
}, [hvmToken, performSignIn])
|
||||
|
||||
const signInForm = (
|
||||
<>
|
||||
<div className="mb-3 mt-1 flex items-center px-3">
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
title="Go back"
|
||||
className="mr-2 flex p-0 text-neutral"
|
||||
onClick={() => setMenuPane(AccountMenuPane.GeneralMenu)}
|
||||
focusable={true}
|
||||
disabled={isSigningIn}
|
||||
/>
|
||||
<div className="text-base font-bold">Sign in</div>
|
||||
</div>
|
||||
<div className="mb-1 px-3">
|
||||
<DecoratedInput
|
||||
className={{ container: `mb-2 ${error ? 'border-danger' : null}` }}
|
||||
@@ -257,6 +290,23 @@ const SignInPane: FunctionComponent<Props> = ({ setMenuPane }) => {
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-3 mt-1 flex items-center px-3">
|
||||
<IconButton
|
||||
icon="arrow-left"
|
||||
title="Go back"
|
||||
className="mr-2 flex p-0 text-neutral"
|
||||
onClick={() => setMenuPane(AccountMenuPane.GeneralMenu)}
|
||||
focusable={true}
|
||||
disabled={isSigningIn}
|
||||
/>
|
||||
<div className="text-base font-bold">{showCaptcha ? 'Human verification' : 'Sign in'}</div>
|
||||
</div>
|
||||
{showCaptcha ? <div className="p-[10px]">{captchaIframe}</div> : signInForm}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(SignInPane)
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
|
||||
import { getPlatformString } from '@/Utils'
|
||||
import { ApplicationEvent, Challenge, removeFromArray, WebAppEvent } from '@standardnotes/snjs'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
Challenge,
|
||||
getErrorMessageFromErrorResponseBody,
|
||||
HttpErrorResponseBody,
|
||||
removeFromArray,
|
||||
WebAppEvent,
|
||||
} from '@standardnotes/snjs'
|
||||
import { alertDialog, isIOS, RouteType } from '@standardnotes/ui-services'
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import Footer from '@/Components/Footer/Footer'
|
||||
@@ -117,7 +124,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
onAppLaunch()
|
||||
}
|
||||
|
||||
const removeAppObserver = application.addEventObserver(async (eventName) => {
|
||||
const removeAppObserver = application.addEventObserver(async (eventName, data?: unknown) => {
|
||||
if (eventName === ApplicationEvent.Started) {
|
||||
onAppStart()
|
||||
} else if (eventName === ApplicationEvent.Launched) {
|
||||
@@ -147,6 +154,14 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
type: ToastType.Error,
|
||||
message: 'Too many requests. Please try again later.',
|
||||
})
|
||||
} else if (eventName === ApplicationEvent.FailedSync) {
|
||||
addToast({
|
||||
type: ToastType.Error,
|
||||
message: getErrorMessageFromErrorResponseBody(
|
||||
data as HttpErrorResponseBody,
|
||||
'Sync error. Please try again later.',
|
||||
),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -23,12 +23,15 @@ const QuickSettingsButton = ({ application, isMobileNavigation = false }: Props)
|
||||
const toggleMenu = () => setIsOpen(!isOpen)
|
||||
|
||||
useEffect(() => {
|
||||
const darkThemeFeature = new UIFeature(GetDarkThemeFeature())
|
||||
|
||||
return commandService.addCommandHandler({
|
||||
command: TOGGLE_DARK_MODE_COMMAND,
|
||||
category: 'General',
|
||||
description: 'Toggle dark mode',
|
||||
onKeyDown: () => {
|
||||
void application.componentManager.toggleTheme(new UIFeature(GetDarkThemeFeature()))
|
||||
void application.componentManager.toggleTheme(darkThemeFeature)
|
||||
return true
|
||||
},
|
||||
})
|
||||
}, [application, commandService])
|
||||
|
||||
@@ -42,6 +42,16 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
}
|
||||
}
|
||||
|
||||
const updateSubscriptionSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||
try {
|
||||
await application.settings.updateSubscriptionSetting(settingName, payload, false)
|
||||
return true
|
||||
} catch (e) {
|
||||
application.alerts.alert(STRING_FAILED_TO_UPDATE_USER_SETTING).catch(console.error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const loadSettings = useCallback(async () => {
|
||||
if (!application.sessions.getUser()) {
|
||||
return
|
||||
@@ -79,7 +89,7 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||
setSignInEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(
|
||||
const updateResult = await updateSubscriptionSetting(
|
||||
SettingName.create(SettingName.NAMES.MuteSignInEmails).getValue(),
|
||||
newValue,
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { convertStringifiedBooleanToBoolean, isDesktopApplication } from '@/Utils'
|
||||
import { isDesktopApplication } from '@/Utils'
|
||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
@@ -6,9 +6,7 @@ import { observer } from 'mobx-react-lite'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import Dropdown from '@/Components/Dropdown/Dropdown'
|
||||
import { DropdownItem } from '@/Components/Dropdown/DropdownItem'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import { EmailBackupFrequency, MuteFailedBackupsEmailsOption, SettingName } from '@standardnotes/snjs'
|
||||
import { EmailBackupFrequency, SettingName } from '@standardnotes/snjs'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import Spinner from '@/Components/Spinner/Spinner'
|
||||
@@ -21,7 +19,6 @@ const EmailBackups = ({ application }: Props) => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [emailFrequency, setEmailFrequency] = useState<EmailBackupFrequency>(EmailBackupFrequency.Disabled)
|
||||
const [emailFrequencyOptions, setEmailFrequencyOptions] = useState<DropdownItem[]>([])
|
||||
const [isFailedBackupEmailMuted, setIsFailedBackupEmailMuted] = useState(true)
|
||||
const hasAccount = application.hasAccount()
|
||||
|
||||
const loadEmailFrequencySetting = useCallback(async () => {
|
||||
@@ -38,14 +35,6 @@ const EmailBackups = ({ application }: Props) => {
|
||||
EmailBackupFrequency.Disabled,
|
||||
),
|
||||
)
|
||||
setIsFailedBackupEmailMuted(
|
||||
convertStringifiedBooleanToBoolean(
|
||||
userSettings.getSettingValue<MuteFailedBackupsEmailsOption>(
|
||||
SettingName.create(SettingName.NAMES.MuteFailedBackupsEmails).getValue(),
|
||||
MuteFailedBackupsEmailsOption.NotMuted,
|
||||
),
|
||||
),
|
||||
)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
@@ -90,19 +79,6 @@ const EmailBackups = ({ application }: Props) => {
|
||||
}
|
||||
}
|
||||
|
||||
const toggleMuteFailedBackupEmails = async () => {
|
||||
const previousValue = isFailedBackupEmailMuted
|
||||
setIsFailedBackupEmailMuted(!isFailedBackupEmailMuted)
|
||||
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.create(SettingName.NAMES.MuteFailedBackupsEmails).getValue(),
|
||||
`${!isFailedBackupEmailMuted}`,
|
||||
)
|
||||
if (!updateResult) {
|
||||
setIsFailedBackupEmailMuted(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
const handleEmailFrequencyChange = (item: string) => {
|
||||
updateEmailFrequency(item as EmailBackupFrequency).catch(console.error)
|
||||
}
|
||||
@@ -132,18 +108,6 @@ const EmailBackups = ({ application }: Props) => {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<Subtitle>Email preferences</Subtitle>
|
||||
<div className="flex justify-between gap-2 md:items-center">
|
||||
<div className="flex flex-col">
|
||||
<Text>Receive a notification email if an email backup fails.</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="h-5 w-5 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch onChange={toggleMuteFailedBackupEmails} checked={!isFailedBackupEmailMuted} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { NativeFeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, useEffect, useState } from 'react'
|
||||
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { FunctionComponent } from 'react'
|
||||
import TwoFactorAuthWrapper from './TwoFactorAuth/TwoFactorAuthWrapper'
|
||||
import { MfaProps } from './TwoFactorAuth/MfaProps'
|
||||
import Encryption from './Encryption'
|
||||
import PasscodeLock from './PasscodeLock'
|
||||
import Privacy from './Privacy'
|
||||
@@ -12,14 +10,33 @@ import ErroredItems from './ErroredItems'
|
||||
import PreferencesPane from '@/Components/Preferences/PreferencesComponents/PreferencesPane'
|
||||
import BiometricsLock from '@/Components/Preferences/Panes/Security/BiometricsLock'
|
||||
import MultitaskingPrivacy from '@/Components/Preferences/Panes/Security/MultitaskingPrivacy'
|
||||
import U2FWrapper from './U2F/U2FWrapper'
|
||||
import { TwoFactorAuth, is2FAEnabled as checkIf2FAIsEnabled } from './TwoFactorAuth/TwoFactorAuth'
|
||||
import U2FView from './U2F/U2FView/U2FView'
|
||||
import TwoFactorAuthView from './TwoFactorAuth/TwoFactorAuthView/TwoFactorAuthView'
|
||||
|
||||
interface SecurityProps extends MfaProps {
|
||||
interface SecurityProps {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
const Security: FunctionComponent<SecurityProps> = (props) => {
|
||||
const isNativeMobileWeb = props.application.isNativeMobileWeb()
|
||||
const [is2FAEnabled, setIs2FAEnabled] = useState(false)
|
||||
const [canDisable2FA, setCanDisable2FA] = useState(true)
|
||||
|
||||
const [auth] = useState(
|
||||
() =>
|
||||
new TwoFactorAuth(props.application.sessions, props.application.mfa, (status) =>
|
||||
setIs2FAEnabled(checkIf2FAIsEnabled(status)),
|
||||
),
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
auth.fetchStatus()
|
||||
}, [auth])
|
||||
|
||||
const onU2FDevicesLoaded = (devices: Array<{ id: string; name: string }>) => {
|
||||
setCanDisable2FA(devices.length === 0)
|
||||
}
|
||||
|
||||
const isU2FFeatureAvailable =
|
||||
props.application.features.getFeatureStatus(
|
||||
@@ -31,8 +48,14 @@ const Security: FunctionComponent<SecurityProps> = (props) => {
|
||||
<Encryption />
|
||||
{props.application.items.invalidNonVaultedItems.length > 0 && <ErroredItems />}
|
||||
<Protections application={props.application} />
|
||||
<TwoFactorAuthWrapper application={props.application} />
|
||||
{isU2FFeatureAvailable && <U2FWrapper application={props.application} />}
|
||||
<TwoFactorAuthView auth={auth} application={props.application} canDisable2FA={canDisable2FA} />
|
||||
{isU2FFeatureAvailable && (
|
||||
<U2FView
|
||||
application={props.application}
|
||||
is2FAEnabled={is2FAEnabled}
|
||||
loadAuthenticatorsCallback={onU2FDevicesLoaded}
|
||||
/>
|
||||
)}
|
||||
{isNativeMobileWeb && <MultitaskingPrivacy application={props.application} />}
|
||||
<PasscodeLock application={props.application} />
|
||||
{isNativeMobileWeb && <BiometricsLock application={props.application} />}
|
||||
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
|
||||
export interface MfaProps {
|
||||
application: WebApplication
|
||||
}
|
||||
+4
@@ -19,6 +19,7 @@ export class TwoFactorAuth {
|
||||
constructor(
|
||||
private readonly sessions: SessionsClientInterface,
|
||||
private readonly mfa: MfaServiceInterface,
|
||||
private callback?: (status: TwoFactorStatus) => void,
|
||||
) {
|
||||
this._errorMessage = null
|
||||
|
||||
@@ -90,6 +91,9 @@ export class TwoFactorAuth {
|
||||
action((active) => {
|
||||
this._status = active ? 'two-factor-enabled' : 'two-factor-disabled'
|
||||
this.setError(null)
|
||||
if (this.callback) {
|
||||
this.callback(this._status)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.catch(
|
||||
|
||||
+3
-2
@@ -16,9 +16,10 @@ import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||
type Props = {
|
||||
auth: TwoFactorAuth
|
||||
application: WebApplication
|
||||
canDisable2FA: boolean
|
||||
}
|
||||
|
||||
const TwoFactorAuthView: FunctionComponent<Props> = ({ auth, application }) => {
|
||||
const TwoFactorAuthView: FunctionComponent<Props> = ({ auth, application, canDisable2FA }) => {
|
||||
const shouldShowActivationModal = auth.status !== 'fetching' && is2FAActivation(auth.status)
|
||||
|
||||
const activationModalTitle = shouldShowActivationModal
|
||||
@@ -96,7 +97,7 @@ const TwoFactorAuthView: FunctionComponent<Props> = ({ auth, application }) => {
|
||||
<TwoFactorTitle auth={auth} />
|
||||
<TwoFactorDescription auth={auth} />
|
||||
</div>
|
||||
<TwoFactorSwitch auth={auth} />
|
||||
<TwoFactorSwitch auth={auth} canDisable2FA={canDisable2FA} />
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
|
||||
|
||||
+5
-2
@@ -6,9 +6,10 @@ import Spinner from '@/Components/Spinner/Spinner'
|
||||
|
||||
type Props = {
|
||||
auth: TwoFactorAuth
|
||||
canDisable2FA: boolean
|
||||
}
|
||||
|
||||
const TwoFactorSwitch: FunctionComponent<Props> = ({ auth }) => {
|
||||
const TwoFactorSwitch: FunctionComponent<Props> = ({ auth, canDisable2FA }) => {
|
||||
if (!auth.isLoggedIn()) {
|
||||
return null
|
||||
}
|
||||
@@ -17,7 +18,9 @@ const TwoFactorSwitch: FunctionComponent<Props> = ({ auth }) => {
|
||||
return <Spinner className="h-4 w-4" />
|
||||
}
|
||||
|
||||
return <Switch checked={!is2FADisabled(auth.status)} onChange={auth.toggle2FA} />
|
||||
const shouldSwitchBeDisabled = auth.status === 'two-factor-enabled' && !canDisable2FA
|
||||
|
||||
return <Switch checked={!is2FADisabled(auth.status)} onChange={auth.toggle2FA} disabled={shouldSwitchBeDisabled} />
|
||||
}
|
||||
|
||||
export default observer(TwoFactorSwitch)
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
import { FunctionComponent, useState } from 'react'
|
||||
import { MfaProps } from './MfaProps'
|
||||
import { TwoFactorAuth } from './TwoFactorAuth'
|
||||
import TwoFactorAuthView from './TwoFactorAuthView/TwoFactorAuthView'
|
||||
|
||||
const TwoFactorAuthWrapper: FunctionComponent<MfaProps> = (props) => {
|
||||
const [auth] = useState(() => new TwoFactorAuth(props.application.sessions, props.application.mfa))
|
||||
auth.fetchStatus()
|
||||
return <TwoFactorAuthView auth={auth} application={props.application} />
|
||||
}
|
||||
|
||||
export default TwoFactorAuthWrapper
|
||||
@@ -1,5 +0,0 @@
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
|
||||
export interface U2FProps {
|
||||
application: WebApplication
|
||||
}
|
||||
+8
-1
@@ -4,7 +4,11 @@ import { observer } from 'mobx-react-lite'
|
||||
import { Text } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { useApplication } from '@/Components/ApplicationProvider'
|
||||
|
||||
const U2FDescription: FunctionComponent = () => {
|
||||
type Props = {
|
||||
is2FAEnabled: boolean
|
||||
}
|
||||
|
||||
const U2FDescription: FunctionComponent<Props> = ({ is2FAEnabled }) => {
|
||||
const application = useApplication()
|
||||
|
||||
if (application.sessions.getUser() === undefined) {
|
||||
@@ -17,6 +21,9 @@ const U2FDescription: FunctionComponent = () => {
|
||||
{!application.isFullU2FClient && (
|
||||
<Text className="italic">Please visit the web app in order to add a hardware security key.</Text>
|
||||
)}
|
||||
{!is2FAEnabled && (
|
||||
<Text className="italic">You must enable two-factor authentication before adding a hardware security key.</Text>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+9
-5
@@ -15,9 +15,11 @@ import RecoveryCodeBanner from '@/Components/RecoveryCodeBanner/RecoveryCodeBann
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
is2FAEnabled: boolean
|
||||
loadAuthenticatorsCallback: (devices: Array<{ id: string; name: string }>) => void
|
||||
}
|
||||
|
||||
const U2FView: FunctionComponent<Props> = ({ application }) => {
|
||||
const U2FView: FunctionComponent<Props> = ({ application, is2FAEnabled, loadAuthenticatorsCallback }) => {
|
||||
const [showDeviceAddingModal, setShowDeviceAddingModal] = useState(false)
|
||||
const [devices, setDevices] = useState<Array<{ id: string; name: string }>>([])
|
||||
const [error, setError] = useState('')
|
||||
@@ -34,8 +36,10 @@ const U2FView: FunctionComponent<Props> = ({ application }) => {
|
||||
return
|
||||
}
|
||||
|
||||
setDevices(authenticatorListOrError.getValue())
|
||||
}, [setError, setDevices, application])
|
||||
const authenticatorList = authenticatorListOrError.getValue()
|
||||
setDevices(authenticatorList)
|
||||
loadAuthenticatorsCallback(authenticatorList)
|
||||
}, [setError, setDevices, application, loadAuthenticatorsCallback])
|
||||
|
||||
useEffect(() => {
|
||||
loadAuthenticatorDevices().catch(console.error)
|
||||
@@ -47,7 +51,7 @@ const U2FView: FunctionComponent<Props> = ({ application }) => {
|
||||
<PreferencesSegment>
|
||||
<div className="flex flex-col">
|
||||
<U2FTitle />
|
||||
<U2FDescription />
|
||||
<U2FDescription is2FAEnabled={is2FAEnabled} />
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
<PreferencesSegment classes="mt-2">
|
||||
@@ -60,7 +64,7 @@ const U2FView: FunctionComponent<Props> = ({ application }) => {
|
||||
/>
|
||||
<Button
|
||||
className="mt-1"
|
||||
disabled={!application.isFullU2FClient}
|
||||
disabled={!application.isFullU2FClient || !is2FAEnabled}
|
||||
label="Add Device"
|
||||
primary
|
||||
onClick={handleAddDeviceClick}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { FunctionComponent } from 'react'
|
||||
|
||||
import { U2FProps } from './U2FProps'
|
||||
import U2FView from './U2FView/U2FView'
|
||||
|
||||
const U2FWrapper: FunctionComponent<U2FProps> = (props) => {
|
||||
return <U2FView application={props.application} />
|
||||
}
|
||||
|
||||
export default U2FWrapper
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user