mirror of
https://github.com/standardnotes/app
synced 2026-09-13 18:46:08 -04:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32c917e6c8 | ||
|
|
9f02329293 | ||
|
|
aa236c784f | ||
|
|
d2a66556e0 | ||
|
|
8deeae5a16 | ||
|
|
0d8a05b805 | ||
|
|
10751ea2ed | ||
|
|
6b774db222 | ||
|
|
be028ff87b | ||
|
|
5f09fc74da | ||
|
|
340f4f7f09 | ||
|
|
371a47d838 | ||
|
|
b839ebb58a | ||
|
|
482c4d1ca4 | ||
|
|
5f96281948 | ||
|
|
2e79fc412c | ||
|
|
5bdbfe9fc7 | ||
|
|
dd8ccdeadc | ||
|
|
eea97362f8 | ||
|
|
01294868c9 | ||
|
|
77ec9ca335 | ||
|
|
3e6c752967 | ||
|
|
ba017d42f5 | ||
|
|
bd3df71dd4 | ||
|
|
22c6e2c56c | ||
|
|
496525ef61 | ||
|
|
6b2f8f3da2 | ||
|
|
e57b28fe29 | ||
|
|
ba4b6a580b | ||
|
|
59fc68296b | ||
|
|
69b2af7612 | ||
|
|
30dda73e90 | ||
|
|
81ea9e896c | ||
|
|
bc9247df41 | ||
|
|
71e8645ca4 | ||
|
|
72f384c215 | ||
|
|
b65e8562f2 | ||
|
|
8ff7fb605a | ||
|
|
3c332a35f6 | ||
|
|
a447fa1ad7 | ||
|
|
76d2d2112b |
@@ -74,7 +74,7 @@ jobs:
|
||||
- name: Compile for AppImage
|
||||
run: yarn run webpack --config desktop.webpack.prod.js
|
||||
- name: AppImage
|
||||
run: yarn run electron-builder --linux --x64 --ia32 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
|
||||
run: yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
|
||||
- name: AppImageX64
|
||||
run: yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
|
||||
- name: AppImageArm64
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
- name: Deb
|
||||
run: |
|
||||
yarn run webpack --config desktop.webpack.prod.js --env deb
|
||||
yarn run electron-builder --linux --x64 --ia32 -c.linux.target=deb --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
|
||||
yarn run electron-builder --linux --x64 -c.linux.target=deb --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
|
||||
- name: DebArm64
|
||||
env:
|
||||
npm_config_target_arch: 'arm64'
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
name: Mobile TestFlight
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*standardnotes/web*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
android:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/mobile
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Export version from package.json
|
||||
run: |
|
||||
echo "PACKAGE_VERSION=$(grep '"version"' ../web/package.json | cut -d '"' -f 4 | cut -d "-" -f 1)" >> $GITHUB_ENV
|
||||
- name: Setup react-native kernel and increase watchers
|
||||
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
|
||||
- name: Decode Dev Android keystore
|
||||
run: |
|
||||
echo "${{ secrets.DEV_KEYSTORE }}" > keystore.keystore.asc
|
||||
gpg -d --passphrase "${{ secrets.DEV_KEYSTORE_PASSPHRASE }}" --batch keystore.keystore.asc > android/app/keystore.keystore
|
||||
- name: Ruby Setup for Fastlane
|
||||
uses: ruby/setup-ruby@v1
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
- run: yarn build:mobile
|
||||
- name: fastlane
|
||||
uses: maierj/[email protected]
|
||||
env:
|
||||
PACKAGE_VERSION: ${{ env.PACKAGE_VERSION }}
|
||||
BUILD_NUMBER: ${{ github.run_number }}
|
||||
ANDROID_KEYSTORE_ALIAS: ${{ secrets.DEV_ANDROID_KEYSTORE_ALIAS }}
|
||||
ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD: ${{ secrets.DEV_ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD }}
|
||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.DEV_ANDROID_KEYSTORE_PASSWORD }}
|
||||
GOOGLE_PLAY_JSON_KEY_DATA: ${{ secrets.GOOGLE_PLAY_JSON_KEY_DATA }}
|
||||
with:
|
||||
lane: 'android dev'
|
||||
subdirectory: 'packages/mobile'
|
||||
ios:
|
||||
env:
|
||||
ITMSTRANSPORTER_FORCE_ITMS_PACKAGE_UPLOAD: true
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/mobile
|
||||
runs-on: macos-11
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Export version from package.json
|
||||
run: |
|
||||
echo "PACKAGE_VERSION=$(grep '"version"' ../web/package.json | cut -d '"' -f 4 | cut -d "-" -f 1)" >> $GITHUB_ENV
|
||||
- name: Ruby Setup for Fastlane
|
||||
uses: ruby/setup-ruby@v1
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable && yarn install:pods
|
||||
- run: yarn build:mobile
|
||||
- name: Set ssh connection to Github
|
||||
uses: webfactory/[email protected]
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
- name: Export Apple AppStore Connect API key
|
||||
run: echo "${{ secrets.APPSTORE_CONNECT_KEY }}" > ios/Authkey.p8
|
||||
- name: Setup fastlane
|
||||
uses: maierj/[email protected]
|
||||
env:
|
||||
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||
with:
|
||||
lane: 'ios setup'
|
||||
subdirectory: 'packages/mobile'
|
||||
- name: fastlane
|
||||
uses: maierj/[email protected]
|
||||
env:
|
||||
PACKAGE_VERSION: ${{ env.PACKAGE_VERSION }}
|
||||
APPLE_APP_ID: ${{ secrets.DEV_APP_APPLE_ID }}
|
||||
APPSTORE_CONNECT_KEY_ID: ${{ secrets.APPSTORE_CONNECT_KEY_ID }}
|
||||
APPSTORE_CONNECT_KEY_ISSUER_ID: ${{ secrets.APPSTORE_CONNECT_KEY_ISSUER_ID }}
|
||||
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
|
||||
FASTLANE_SESSION: ${{ secrets.FASTLANE_SESSION }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
MATCH_CERTIFICATES_URL: ${{ secrets.MATCH_CERTIFICATES_URL }}
|
||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
|
||||
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
|
||||
BUILD_NUMBER: ${{ github.run_number }}
|
||||
with:
|
||||
lane: 'ios dev'
|
||||
subdirectory: 'packages/mobile'
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
aws-region: us-east-1
|
||||
- name: Deploy static site to S3 bucket
|
||||
run: aws s3 sync packages/web/dist/ s3://app.standardnotes.com --delete
|
||||
- name: Invalidate CloudFront Cache on .COM
|
||||
- name: Invalidate CloudFront Cache
|
||||
uses: chetan/invalidate-cloudfront-action@master
|
||||
env:
|
||||
DISTRIBUTION: ${{ secrets.WEBAPP_CLOUDFRONT_COM_DISTRIBUTION_ID }}
|
||||
@@ -53,14 +53,6 @@ jobs:
|
||||
AWS_REGION: 'us-east-1'
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
- name: Invalidate CloudFront Cache on .ORG
|
||||
uses: chetan/invalidate-cloudfront-action@master
|
||||
env:
|
||||
DISTRIBUTION: ${{ secrets.WEBAPP_CLOUDFRONT_ORG_DISTRIBUTION_ID }}
|
||||
PATHS: '/*'
|
||||
AWS_REGION: 'us-east-1'
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
notify_discord:
|
||||
needs: deploy
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -37,7 +37,7 @@ Join us on
|
||||
|
||||
- [Discord](https://standardnotes.com/discord)
|
||||
- [Twitter](https://twitter.com/StandardNotes)
|
||||
- [Forum](https://forum.standardnotes.org)
|
||||
- [Forum](https://standardnotes.com/forum)
|
||||
|
||||
Developers can create and publish their own extensions. Visit the [documentation hub](https://docs.standardnotes.com/) to learn more.
|
||||
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ Thank you for your work in helping keep Standard Notes safe and secure. If you b
|
||||
# Disclosure Policy
|
||||
|
||||
- Let us know as soon as possible upon discovery of a potential security issue, and we'll make every
|
||||
effort to quickly resolve the issue. Please email [security@standardnotes.org](mailto:security@standardnotes.org) for a direct response.
|
||||
effort to quickly resolve the issue. Please email [security@standardnotes.com](mailto:security@standardnotes.com) for a direct response.
|
||||
- Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a
|
||||
third-party. We may publicly disclose the issue before resolving it, if appropriate.
|
||||
third-party. We may publicly disclose the issue before resolving it, if appropriate.
|
||||
- Make a good faith effort to avoid privacy violations, destruction of data, and interruption or
|
||||
degradation of our service. Only interact with accounts you own or with explicit permission of the
|
||||
account holder.
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
"build:services": "yarn workspaces foreach -pt --topological-dev --verbose -R --from @standardnotes/services run build",
|
||||
"build:api": "yarn workspaces foreach -pt --topological-dev --verbose -R --from @standardnotes/api run build",
|
||||
"start:server:web": "lerna run start --scope=@standardnotes/web",
|
||||
"start:server:e2e": "lerna run start:test-server --scope=@standardnotes/snjs",
|
||||
"e2e": "lerna run start:test-server --scope=@standardnotes/snjs",
|
||||
"reset": "find . -type dir -name node_modules | xargs rm -rf && rm -rf yarn.lock && yarn install",
|
||||
"release:prod": "lerna version --conventional-commits --yes -m \"chore(release): publish\"",
|
||||
"publish:prod": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.23.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **snjs:** add account recovery e2e test suite ([#2134](https://github.com/standardnotes/app/issues/2134)) ([8deeae5](https://github.com/standardnotes/app/commit/8deeae5a16191da7b4aad2ddc568e714fbeef8b8))
|
||||
|
||||
# [1.22.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **snjs:** add sign in with recovery codes use case ([#2130](https://github.com/standardnotes/app/issues/2130)) ([be028ff](https://github.com/standardnotes/app/commit/be028ff87bb5306fc266b70567cbea8a13547e7e))
|
||||
|
||||
## [1.21.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.21.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.21.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.21.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.21.1",
|
||||
"version": "1.23.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export enum AuthApiOperations {
|
||||
GenerateRecoveryCodes,
|
||||
GetRecoveryKeyParams,
|
||||
SignInWithRecoveryCodes,
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { ApiVersion } from '../../Api'
|
||||
import { ApiCallError } from '../../Error/ApiCallError'
|
||||
import { ErrorMessage } from '../../Error/ErrorMessage'
|
||||
import {
|
||||
GenerateRecoveryCodesResponse,
|
||||
RecoveryKeyParamsResponse,
|
||||
SignInWithRecoveryCodesResponse,
|
||||
} from '../../Response'
|
||||
import { AuthServerInterface } from '../../Server'
|
||||
|
||||
import { AuthApiOperations } from './AuthApiOperations'
|
||||
import { AuthApiServiceInterface } from './AuthApiServiceInterface'
|
||||
|
||||
export class AuthApiService implements AuthApiServiceInterface {
|
||||
private operationsInProgress: Map<AuthApiOperations, boolean>
|
||||
|
||||
constructor(private authServer: AuthServerInterface) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
|
||||
async generateRecoveryCodes(): Promise<GenerateRecoveryCodesResponse> {
|
||||
if (this.operationsInProgress.get(AuthApiOperations.GenerateRecoveryCodes)) {
|
||||
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||
}
|
||||
|
||||
this.operationsInProgress.set(AuthApiOperations.GenerateRecoveryCodes, true)
|
||||
|
||||
try {
|
||||
const response = await this.authServer.generateRecoveryCodes()
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
throw new ApiCallError(ErrorMessage.GenericFail)
|
||||
} finally {
|
||||
this.operationsInProgress.set(AuthApiOperations.GenerateRecoveryCodes, false)
|
||||
}
|
||||
}
|
||||
|
||||
async recoveryKeyParams(dto: {
|
||||
username: string
|
||||
codeChallenge: string
|
||||
recoveryCodes: string
|
||||
}): Promise<RecoveryKeyParamsResponse> {
|
||||
if (this.operationsInProgress.get(AuthApiOperations.GetRecoveryKeyParams)) {
|
||||
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||
}
|
||||
|
||||
this.operationsInProgress.set(AuthApiOperations.GetRecoveryKeyParams, true)
|
||||
|
||||
try {
|
||||
const response = await this.authServer.recoveryKeyParams({
|
||||
api_version: ApiVersion.v0,
|
||||
code_challenge: dto.codeChallenge,
|
||||
recovery_codes: dto.recoveryCodes,
|
||||
username: dto.username,
|
||||
})
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
throw new ApiCallError(ErrorMessage.GenericFail)
|
||||
} finally {
|
||||
this.operationsInProgress.set(AuthApiOperations.GetRecoveryKeyParams, false)
|
||||
}
|
||||
}
|
||||
|
||||
async signInWithRecoveryCodes(dto: {
|
||||
username: string
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
}): Promise<SignInWithRecoveryCodesResponse> {
|
||||
if (this.operationsInProgress.get(AuthApiOperations.SignInWithRecoveryCodes)) {
|
||||
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||
}
|
||||
|
||||
this.operationsInProgress.set(AuthApiOperations.SignInWithRecoveryCodes, true)
|
||||
|
||||
try {
|
||||
const response = await this.authServer.signInWithRecoveryCodes({
|
||||
api_version: ApiVersion.v0,
|
||||
code_verifier: dto.codeVerifier,
|
||||
password: dto.password,
|
||||
recovery_codes: dto.recoveryCodes,
|
||||
username: dto.username,
|
||||
})
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
throw new ApiCallError(ErrorMessage.GenericFail)
|
||||
} finally {
|
||||
this.operationsInProgress.set(AuthApiOperations.SignInWithRecoveryCodes, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import {
|
||||
GenerateRecoveryCodesResponse,
|
||||
RecoveryKeyParamsResponse,
|
||||
SignInWithRecoveryCodesResponse,
|
||||
} from '../../Response'
|
||||
|
||||
export interface AuthApiServiceInterface {
|
||||
generateRecoveryCodes(): Promise<GenerateRecoveryCodesResponse>
|
||||
recoveryKeyParams(dto: {
|
||||
username: string
|
||||
codeChallenge: string
|
||||
recoveryCodes: string
|
||||
}): Promise<RecoveryKeyParamsResponse>
|
||||
signInWithRecoveryCodes(dto: {
|
||||
username: string
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
}): Promise<SignInWithRecoveryCodesResponse>
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
export * from './Auth/AuthApiOperations'
|
||||
export * from './Auth/AuthApiService'
|
||||
export * from './Auth/AuthApiServiceInterface'
|
||||
export * from './Authenticator/AuthenticatorApiOperations'
|
||||
export * from './Authenticator/AuthenticatorApiService'
|
||||
export * from './Authenticator/AuthenticatorApiServiceInterface'
|
||||
|
||||
@@ -1 +1 @@
|
||||
export type HttpRequestParams = Record<string, unknown>
|
||||
export type HttpRequestParams = unknown
|
||||
|
||||
@@ -276,9 +276,9 @@ export class HttpService implements HttpServiceInterface {
|
||||
}
|
||||
|
||||
private urlForUrlAndParams(url: string, params: HttpRequestParams) {
|
||||
const keyValueString = Object.keys(params)
|
||||
const keyValueString = Object.keys(params as Record<string, unknown>)
|
||||
.map((key) => {
|
||||
return key + '=' + encodeURIComponent(params[key] as string)
|
||||
return key + '=' + encodeURIComponent((params as Record<string, unknown>)[key] as string)
|
||||
})
|
||||
.join('&')
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface RecoveryKeyParamsRequestParams {
|
||||
api_version: string
|
||||
username: string
|
||||
code_challenge: string
|
||||
recovery_codes: string
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface SignInWithRecoveryCodesRequestParams {
|
||||
api_version: string
|
||||
username: string
|
||||
password: string
|
||||
code_verifier: string
|
||||
recovery_codes: string
|
||||
}
|
||||
@@ -5,6 +5,8 @@ export * from './Authenticator/GenerateAuthenticatorRegistrationOptionsRequestPa
|
||||
export * from './Authenticator/ListAuthenticatorsRequestParams'
|
||||
export * from './Authenticator/VerifyAuthenticatorAuthenticationResponseRequestParams'
|
||||
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseRequestParams'
|
||||
export * from './Recovery/RecoveryKeyParamsRequestParams'
|
||||
export * from './Recovery/SignInWithRecoveryCodesRequestParams'
|
||||
export * from './Subscription/AppleIAPConfirmRequestParams'
|
||||
export * from './Subscription/SubscriptionInviteAcceptRequestParams'
|
||||
export * from './Subscription/SubscriptionInviteCancelRequestParams'
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
|
||||
import { GenerateRecoveryCodesResponseBody } from './GenerateRecoveryCodesResponseBody'
|
||||
|
||||
export interface GenerateRecoveryCodesResponse extends HttpResponse {
|
||||
data: Either<GenerateRecoveryCodesResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface GenerateRecoveryCodesResponseBody {
|
||||
recoveryCodes: string
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
|
||||
import { RecoveryKeyParamsResponseBody } from './RecoveryKeyParamsResponseBody'
|
||||
|
||||
export interface RecoveryKeyParamsResponse extends HttpResponse {
|
||||
data: Either<RecoveryKeyParamsResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { KeyParamsData } from '@standardnotes/responses'
|
||||
|
||||
export interface RecoveryKeyParamsResponseBody {
|
||||
keyParams: KeyParamsData
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
|
||||
import { SignInWithRecoveryCodesResponseBody } from './SignInWithRecoveryCodesResponseBody'
|
||||
|
||||
export interface SignInWithRecoveryCodesResponse extends HttpResponse {
|
||||
data: Either<SignInWithRecoveryCodesResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { KeyParamsData, SessionBody } from '@standardnotes/responses'
|
||||
|
||||
export interface SignInWithRecoveryCodesResponseBody {
|
||||
session: SessionBody
|
||||
key_params: KeyParamsData
|
||||
user: {
|
||||
uuid: string
|
||||
email: string
|
||||
protocolVersion: string
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,12 @@ export * from './Authenticator/VerifyAuthenticatorAuthenticationResponseResponse
|
||||
export * from './Authenticator/VerifyAuthenticatorAuthenticationResponseResponseBody'
|
||||
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseResponse'
|
||||
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseResponseBody'
|
||||
export * from './Recovery/GenerateRecoveryCodesResponse'
|
||||
export * from './Recovery/GenerateRecoveryCodesResponseBody'
|
||||
export * from './Recovery/RecoveryKeyParamsResponse'
|
||||
export * from './Recovery/RecoveryKeyParamsResponseBody'
|
||||
export * from './Recovery/SignInWithRecoveryCodesResponse'
|
||||
export * from './Recovery/SignInWithRecoveryCodesResponseBody'
|
||||
export * from './Subscription/AppleIAPConfirmResponse'
|
||||
export * from './Subscription/AppleIAPConfirmResponseBody'
|
||||
export * from './Subscription/SubscriptionInviteAcceptResponse'
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
||||
import { RecoveryKeyParamsRequestParams, SignInWithRecoveryCodesRequestParams } from '../../Request'
|
||||
import {
|
||||
GenerateRecoveryCodesResponse,
|
||||
RecoveryKeyParamsResponse,
|
||||
SignInWithRecoveryCodesResponse,
|
||||
} from '../../Response'
|
||||
import { AuthServerInterface } from './AuthServerInterface'
|
||||
import { Paths } from './Paths'
|
||||
|
||||
export class AuthServer implements AuthServerInterface {
|
||||
constructor(private httpService: HttpServiceInterface) {}
|
||||
|
||||
async generateRecoveryCodes(): Promise<GenerateRecoveryCodesResponse> {
|
||||
const response = await this.httpService.post(Paths.v1.generateRecoveryCodes)
|
||||
|
||||
return response as GenerateRecoveryCodesResponse
|
||||
}
|
||||
|
||||
async recoveryKeyParams(params: RecoveryKeyParamsRequestParams): Promise<RecoveryKeyParamsResponse> {
|
||||
const response = await this.httpService.post(Paths.v1.recoveryKeyParams, params)
|
||||
|
||||
return response as RecoveryKeyParamsResponse
|
||||
}
|
||||
|
||||
async signInWithRecoveryCodes(
|
||||
params: SignInWithRecoveryCodesRequestParams,
|
||||
): Promise<SignInWithRecoveryCodesResponse> {
|
||||
const response = await this.httpService.post(Paths.v1.signInWithRecoveryCodes, params)
|
||||
|
||||
return response as SignInWithRecoveryCodesResponse
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { RecoveryKeyParamsRequestParams, SignInWithRecoveryCodesRequestParams } from '../../Request'
|
||||
import {
|
||||
GenerateRecoveryCodesResponse,
|
||||
RecoveryKeyParamsResponse,
|
||||
SignInWithRecoveryCodesResponse,
|
||||
} from '../../Response'
|
||||
|
||||
export interface AuthServerInterface {
|
||||
generateRecoveryCodes(): Promise<GenerateRecoveryCodesResponse>
|
||||
recoveryKeyParams(params: RecoveryKeyParamsRequestParams): Promise<RecoveryKeyParamsResponse>
|
||||
signInWithRecoveryCodes(params: SignInWithRecoveryCodesRequestParams): Promise<SignInWithRecoveryCodesResponse>
|
||||
}
|
||||
@@ -2,8 +2,15 @@ const SessionPaths = {
|
||||
refreshSession: '/v1/sessions/refresh',
|
||||
}
|
||||
|
||||
const RecoveryPaths = {
|
||||
generateRecoveryCodes: '/v1/recovery/codes',
|
||||
recoveryKeyParams: '/v1/recovery/login-params',
|
||||
signInWithRecoveryCodes: '/v1/recovery/login',
|
||||
}
|
||||
|
||||
export const Paths = {
|
||||
v1: {
|
||||
...SessionPaths,
|
||||
...RecoveryPaths,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from './Auth/AuthServer'
|
||||
export * from './Auth/AuthServerInterface'
|
||||
export * from './Authenticator/AuthenticatorServer'
|
||||
export * from './Authenticator/AuthenticatorServerInterface'
|
||||
export * from './Subscription/SubscriptionServer'
|
||||
|
||||
@@ -3,6 +3,66 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.104.79](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.78](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.77](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.76](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.75](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.74](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.73](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.72](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.71](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.70](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.69](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.67](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.104.63",
|
||||
"version": "3.104.79",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.2.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/docs
|
||||
|
||||
## [0.2.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/docs
|
||||
|
||||
## [0.2.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -154,7 +154,7 @@ When possible, use path names when linking between docs (see #1 above). This imp
|
||||
Please follow the following writing style guide. These guidelines are open for discussion and are subject to change as we see fit, but we should be consistent about them:
|
||||
|
||||
- Add periods to complete sentences in lists.
|
||||
- Use "sign in to" instead of "sign into" to be consistent with the [web app](https://app.standardnotes.org).
|
||||
- Use "sign in to" instead of "sign into" to be consistent with the [web app](https://app.standardnotes.com).
|
||||
- Hyphenate `open-source` when using the phrase as an adjective (see [Merriam-Webster's](https://www.merriam-webster.com/dictionary/open-source)).
|
||||
- The _-n't_ contractions are fine, but try to avoid using noun-verb contractions, such as ("you're" or "you've"). (See [Google's convention](https://developers.google.com/style/contractions)).
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@ hide_table_of_contents: false
|
||||
|
||||
Thank you for your interest in contributing to Standard Notes. We are very happy that you want to help. The development for all our apps are done publicly on [GitHub](https://github.com/standardnotes). Here are some ways that you can help us improve Standard Notes:
|
||||
|
||||
1. Submit suggestions and feature ideas to our [community forum](https://forum.standardnotes.org). You can comment on the existing feature requests and subscribe to individual threads to follow their progress.
|
||||
2. Report bugs or issues to our [community forum](https://forum.standardnotes.org).
|
||||
1. Submit suggestions and feature ideas to our [community forum](https://standardnotes.com/forum). You can comment on the existing feature requests and subscribe to individual threads to follow their progress.
|
||||
2. Report bugs or issues to our [community forum](https://standardnotes.com/forum).
|
||||
3. Help others on the forum and our [Discord group](https://standardnotes.com/discord).
|
||||
4. Blog, tweet and share what you like about Standard Notes, what you use it for, and how it helps you.
|
||||
|
||||
We do things the old-fashioned way and rely on people like you telling other people like you about Standard Notes to sustain our efforts. Get a free month of Extended when your friend also joins Extended. Log into the [member dashboard](https://dashboard.standardnotes.com) to get your unique referral link. 🙂
|
||||
|
||||
@@ -57,7 +57,7 @@ In this example, we'll use our blank-slate ReactJS template to build a utility b
|
||||
|
||||
1. You should now see "Blank Slate" at the bottom left of your notes. Clicking on it should raise a little window which displays "Your component is ready". If you try in your browser, it is possible that the window instead remains white. This is most likely due to your browser blocking Mixed Content page. Search online for how to enable it for your browser.
|
||||
|
||||
More detailed instructions on setting up your local environment can be found in the [Local Setup tutorial](/extensions/local-setup).
|
||||
More detailed instructions on setting up your local environment can be found in the [Local Setup tutorial](/extensions/local-setup/).
|
||||
|
||||
## Writing the App
|
||||
|
||||
@@ -136,8 +136,8 @@ Areas tell Standard Notes where to display a particular component. The current l
|
||||
|
||||
There are an unlimited number of things you can build with components that do anything from nested folders in the tags pane and autocomplete in the editor pane, to pushing notes to GitHub or WordPress.
|
||||
|
||||
To see how we built [our own components](https://standardnotes.com/extensions), study the source code [available here](https://github.com/sn-extensions).
|
||||
To see how we built [our own components](https://standardnotes.com/features), study the source code [available here](https://github.com/standardnotes/plugins).
|
||||
|
||||
For questions on development, [post in the forum](https://forum.standardnotes.org) or [join our Discord](https://standardnotes.com/discord).
|
||||
For questions on development, [post in the forum](https://standardnotes.com/forum) or [join our Discord](https://standardnotes.com/discord).
|
||||
|
||||
If you'd like to support Standard Notes and use our secure hosting to install all the components we have to offer, consider purchasing the [Extended subscription](https://standardnotes.com/extended).
|
||||
If you'd like to support Standard Notes and use our secure hosting to install all the components we have to offer, consider purchasing the [Extended subscription](https://standardnotes.com/plans).
|
||||
|
||||
@@ -53,4 +53,4 @@ We use AGPL-3.0-or-later to protect the community. Without the license, large te
|
||||
|
||||
Operating systems such as MacOS, Windows, and Linux allow users to build their own desktop apps and run them on their computer as they please. Similarly, Standard Notes allows developers to build their own editors and use them in their Standard Notes app as they please. Therefore, you can think of Standard Notes as an operating system. The possibilities for building editors (apps) for the Standard Notes operating system are almost endless. Some possibilities to get you started include editors for code, markdown, rich text, passwords, bookmarks, calendars, charts, grids, kanban boards, presentation slides, spreadsheets, timelines, to-do lists, two-factor authentication codes, and other structured secrets. Think of a problem that you want to solve, and try building an editor to solve it.
|
||||
|
||||
[Get Started with Building Editors →](./editors-getting-started.md)
|
||||
[Get Started with Building Editors →](./editors-getting-started.md/)
|
||||
|
||||
@@ -23,22 +23,22 @@ Rather than tightly couple every feature we dream of building for Standard Notes
|
||||
|
||||
## Sustainability
|
||||
|
||||
The Extensions model is also our main fundraising method, and allows us to to offer our core privacy experience at no cost, while sustaining future development by offering advanced features through our [Extended](https://standardnotes.com/extended) program.
|
||||
The Extensions model is also our main fundraising method, and allows us to to offer our core privacy experience at no cost, while sustaining future development by offering advanced features through our [Extended](https://standardnotes.com/plans) program.
|
||||
|
||||
Most of our extensions are [open-source](https://github.com/sn-extensions) and available for self-hosting. You can also learn to develop your own extensions by following the guides on this site. However, we encourage you to support the sustainability and future development of this project by [purchasing a subscription](https://standardnotes.com/extensions).
|
||||
Most of our extensions are [open-source](https://github.com/standardnotes/plugins) and available for self-hosting. You can also learn to develop your own extensions by following the guides on this site. However, we encourage you to support the sustainability and future development of this project by [purchasing a subscription](https://standardnotes.com/plans).
|
||||
|
||||
## Types
|
||||
|
||||
There are 3 main types of extensions:
|
||||
|
||||
1. **Components**: Components are user interface elements that completely swap out areas of Standard Notes with custom behavior. Components include editors (such as the [Markdown Pro Editor](https://standardnotes.com/extensions/markdown-pro) and [Plus Editor](https://standardnotes.com/extensions/plus-editor)), editor stack components (like the [Action Bar](https://standardnotes.com/extensions/action-bar) and [FileSafe](https://standardnotes.com/extensions/filesafe)), and other components (like [Folders](https://standardnotes.com/extensions/folders) and [Quick Tags](https://standardnotes.com/extensions/quick-tags)).
|
||||
1. **Components**: Components are user interface elements that completely swap out areas of Standard Notes with custom behavior. Components include editors (such as the [Markdown Pro Editor](https://standardnotes.com/features/markdown-pro) and [Plus Editor](https://standardnotes.com/features/plus-editor)), editor stack components (like the [Action Bar](https://standardnotes.com/features/action-bar) and [FileSafe](https://standardnotes.com/features/filesafe)), and other components (like [Folders](https://standardnotes.com/features/folders) and [Quick Tags](https://standardnotes.com/features/quick-tags)).
|
||||
|
||||
**[Develop a component →](/extensions/building-an-extension)**
|
||||
**[Develop a component →](/extensions/building-an-extension/)**
|
||||
|
||||
2. **Themes**: Themes change the visual appearance of Standard Notes, and are compatible on all platforms, including desktop, web, and mobile. Some of our own themes include [Midnight](https://standardnotes.com/extensions/midnight) and [Solarized Dark](https://standardnotes.com/extensions/solarized-dark).
|
||||
2. **Themes**: Themes change the visual appearance of Standard Notes, and are compatible on all platforms, including desktop, web, and mobile. Some of our own themes include [Midnight](https://standardnotes.com/features/midnight) and [Solarized Dark](https://standardnotes.com/features/solarized-dark).
|
||||
|
||||
**[Develop a theme →](/extensions/themes)**
|
||||
**[Develop a theme →](/extensions/themes/)**
|
||||
|
||||
3. **Actions**: Actions are an API-based extension interface that are accessible via the Actions menu in the note pane. Actions are triggered manually by the user by selecting an action from the list, and have the ability to interface with the current note and send or retrieve content from a remote server. We use actions for places such as [Listed](https://listed.to), which is our blogging platform for Standard Notes users.
|
||||
|
||||
**[Develop an action →](/extensions/actions)**
|
||||
**[Develop an action →](/extensions/actions/)**
|
||||
|
||||
@@ -42,7 +42,7 @@ To get your extension running locally, both of these components must be hosted o
|
||||
|
||||
1. In your extension's root directory, create a file called `ext.json`.
|
||||
|
||||
1. Place, at minimum, the following key/value pairs. For the full listing of keys, see the [Publishing guide](/extensions/publishing).
|
||||
1. Place, at minimum, the following key/value pairs. For the full listing of keys, see the [Publishing guide](/extensions/publishing/).
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -56,7 +56,7 @@ To get your extension running locally, both of these components must be hosted o
|
||||
```
|
||||
|
||||
The `url` should point to where your extension's index.html is hosted on your local server.
|
||||
The `area` describes what kind of extension this will be. A list of valid values can be found in the [Publishing guide](/extensions/publishing).
|
||||
The `area` describes what kind of extension this will be. A list of valid values can be found in the [Publishing guide](/extensions/publishing/).
|
||||
|
||||
1. In your browser, open http://localhost:8001/ext.json and make sure you see the JSON file content from above.
|
||||
|
||||
@@ -82,4 +82,4 @@ If you're creating a theme, you would follow the same instructions, and for `are
|
||||
|
||||
### Publishing
|
||||
|
||||
Once you're ready to ship your extension in a production environment, check out the [Publishing guide](/extensions/publishing) to learn more about configuring your extension to autoupdate and be installed in an offline environment.
|
||||
Once you're ready to ship your extension in a production environment, check out the [Publishing guide](/extensions/publishing/) to learn more about configuring your extension to autoupdate and be installed in an offline environment.
|
||||
|
||||
@@ -38,7 +38,7 @@ metatype: json
|
||||
"url": "https://domain.org/link-to-hosted-extension",
|
||||
"download_url": "https://github.com/sn-extensions/advanced-markdown-editor/archive/1.0.184.zip",
|
||||
"latest_url": "https://listed.to/my-extension-json-link",
|
||||
"marketing_url": "https://standardnotes.com/extensions/advanced-markdown",
|
||||
"marketing_url": "https://standardnotes.com/features/advanced-markdown",
|
||||
"thumbnail_url": "https://domain.org/editors/adv-markdown.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ hide_table_of_contents: false
|
||||
|
||||
Each of the Standard Notes themes use a common set of CSS variables. With the Standard Notes StyleKit, you can use those variables inside the editors.
|
||||
|
||||
You can find a list of variables [here](/extensions/themes).
|
||||
You can find a list of variables [here](/extensions/themes/).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Themes allow you to customize the look and feel of the Standard Notes app on all
|
||||
|
||||
You can view the [source code](https://github.com/sn-extensions/solarized-dark-theme) of our official themes in order to best understand how to create your own theme.
|
||||
|
||||
For how to install a theme, please see [Publishing](/extensions/publishing).
|
||||
For how to install a theme, please see [Publishing](/extensions/publishing/).
|
||||
|
||||
## Creating a theme
|
||||
|
||||
@@ -155,7 +155,7 @@ _Note that font and font sizes do not apply to mobile; only desktop/web._
|
||||
--link-element-color: var(--sn-stylekit-info-color);
|
||||
```
|
||||
|
||||
In order to get SN to display a dock icon for your theme (a circle in the lower right corner of the app that allows you to quickly toggle themes), add the following payload into the your ext.json file when [publishing your theme](/extensions/publishing):
|
||||
In order to get SN to display a dock icon for your theme (a circle in the lower right corner of the app that allows you to quickly toggle themes), add the following payload into the your ext.json file when [publishing your theme](/extensions/publishing/):
|
||||
|
||||
```json
|
||||
"dock_icon": {
|
||||
@@ -176,4 +176,4 @@ Since v3.9.15, the items in the notes list use a new variable for the background
|
||||
|
||||
## Licensing
|
||||
|
||||
Our themes are provided open-source mainly for educational and quality purposes. You're free to install them on your own servers, but please consider subscribing to [Standard Notes Extended](https://standardnotes.com/extensions) to help sustain future development of the Standard Notes ecosystem.
|
||||
Our themes are provided open-source mainly for educational and quality purposes. You're free to install them on your own servers, but please consider subscribing to [Standard Notes Extended](https://standardnotes.com/plans) to help sustain future development of the Standard Notes ecosystem.
|
||||
|
||||
@@ -178,7 +178,7 @@ Due to mounted volumes, we recommend running the setup as a root user. If you wi
|
||||
1. Once the server has finished rebooting, log back into the server and start the Standard Notes server process:
|
||||
|
||||
```shell
|
||||
cd standalone
|
||||
cd self-hosted
|
||||
./server.sh start
|
||||
```
|
||||
|
||||
@@ -226,7 +226,7 @@ Due to mounted volumes, we recommend running the setup as a root user. If you wi
|
||||
|
||||
## Securing your server
|
||||
|
||||
To start using your new server with the Standard Notes app at `app.standardnotes.com,` you have to configure an HTTPS reverse proxy. Head over to [Securing HTTP traffic of your Sync server](./https-support.md) for more information on how to set up a reverse proxy.
|
||||
To start using your new server with the Standard Notes app at `app.standardnotes.com,` you have to configure an HTTPS reverse proxy. Head over to [Securing HTTP traffic of your Sync server](./https-support.md/) for more information on how to set up a reverse proxy.
|
||||
|
||||
## Using your new server
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ hide_table_of_contents: false
|
||||
|
||||
## Requirements
|
||||
|
||||
In order to upload files you have to have an active subscription for your user. Read the [subscriptions](./subscriptions.md) page on instructions how to setup a subscription for yourself.
|
||||
In order to upload files you have to have an active subscription for your user. Read the [subscriptions](./subscriptions.md/) page on instructions how to setup a subscription for yourself.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ The web application is an optional process that you must spin up separately. How
|
||||
|
||||
The fastest and easiest way to get up and running is to use our automated Docker setup. All you need is a Linux server and the latest version of [Docker](https://docs.docker.com/get-started).
|
||||
|
||||
[Check out our Docker instructions page to get started →](./docker.md)
|
||||
[Check out our Docker instructions page to get started →](./docker.md/)
|
||||
|
||||
:::
|
||||
|
||||
@@ -68,5 +68,5 @@ If you would like to self-host the actual Standard Notes web application, visit
|
||||
|
||||
## Self-hosting without Docker?
|
||||
|
||||
Configuring the full Standard Notes architecture manually can be challenging without detailed study. We do not offer support for this method of self-hosting. [The only supported self-hosting method is to use Docker →](./docker.md)
|
||||
Configuring the full Standard Notes architecture manually can be challenging without detailed study. We do not offer support for this method of self-hosting. [The only supported self-hosting method is to use Docker →](./docker.md/)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ These instructions will enable you to secure HTTP traffic of your standalone inf
|
||||
|
||||
#### Pre-requisites
|
||||
|
||||
- Your standalone infrastructure is running on our [docker](./docker.md) setup
|
||||
- Your standalone infrastructure is running on our [docker](./docker.md/) setup
|
||||
- You've installed `nginx` in your server.
|
||||
- You've configured a domain name (or subdomain) to point to your server's IP address.
|
||||
|
||||
|
||||
@@ -44,4 +44,4 @@ Run:
|
||||
|
||||
In order to import your data to the database that our Standalone setup will create, just place your `dbdump.sql` file inside the `path-to-your-standalone/data/import` folder. The data will be imported once the setups starts.
|
||||
|
||||
To proceed, head over to our [Self-hosting with Docker](./docker.md) page.
|
||||
To proceed, head over to our [Self-hosting with Docker](./docker.md/) page.
|
||||
|
||||
@@ -22,7 +22,7 @@ hide_table_of_contents: false
|
||||
|
||||
These instructions make the following assumptions:
|
||||
|
||||
- You have an existing standalone infrastructure running with our [docker setup](./docker.md)
|
||||
- You have an existing standalone infrastructure running with our [docker setup](./docker.md/)
|
||||
|
||||
## Updating
|
||||
|
||||
|
||||
@@ -157,6 +157,6 @@ For every received item:
|
||||
|
||||
Join the [Discord group](https://standardnotes.com/discord) to discuss implementation details and ask any questions you may have.
|
||||
|
||||
You can also email [help@standardnotes.org](mailto:[email protected]).
|
||||
You can also email [help@standardnotes.com](mailto:[email protected]).
|
||||
|
||||
Follow [@standardnotes on Twitter](https://twitter.com/standardnotes) for updates and announcements.
|
||||
|
||||
@@ -17,7 +17,7 @@ hide_table_of_contents: false
|
||||
|
||||
The 004 protocol upgrade centers around a system that makes it easy and painless to upgrade to a future protocol version, as well as more modern cryptographic primitives.
|
||||
|
||||
This page is a copy of the specification file located at [github.com/standardnotes/snjs](https://github.com/standardnotes/snjs/blob/master/packages/snjs/specification.md).
|
||||
This page is a copy of the specification file located at [github.com/standardnotes/snjs](https://github.com/standardnotes/app/blob/main/packages/snjs/specification.md).
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -338,8 +338,8 @@ result = ['004', nonce, ciphertext, encoded_authenticated_data].join(':')
|
||||
|
||||
## Next Steps
|
||||
|
||||
Join the [Discord group](https://standardnotes.com/Discord) to discuss implementation details and ask any questions you may have.
|
||||
Join the [Discord group](https://standardnotes.com/discord) to discuss implementation details and ask any questions you may have.
|
||||
|
||||
You can also email [help@standardnotes.org](mailto:[email protected]).
|
||||
You can also email [help@standardnotes.com](mailto:[email protected]).
|
||||
|
||||
Follow [@standardnotes on Twitter](https://twitter.com/standardnotes) for updates and announcements.
|
||||
|
||||
@@ -26,7 +26,7 @@ hide_table_of_contents: false
|
||||
We are aware of issues with importing backups belonging to another account when that account is still registered, such as when you are [changing your account email](https://standardnotes.com/help/7/how-can-i-change-my-account-email). If you are signed in to your new account, some tags are duplicated and are not properly assigned to notes and a significant number of notes, tags and/or editors are not imported. We are working on a fix. As a temporary workaround, you can import the backup while signed out of the app before signing in to the new account. Then, when you sign in, choose to merge local data (this is an option that is on by default).
|
||||
|
||||
:::note
|
||||
For the best experience, use a backup that was exported from the [web](https://app.standardnotes.org) or desktop app. A backup that was generated from [CloudLink](https://standardnotes.com/help/27/how-do-i-enable-dropbox-google-drive-or-onedrive-backups) may not work as well.
|
||||
For the best experience, use a backup that was exported from the [web](https://app.standardnotes.com) or desktop app. A backup that was generated from [CloudLink](https://standardnotes.com/help/27/how-do-i-enable-dropbox-google-drive-or-onedrive-backups) may not work as well.
|
||||
:::
|
||||
|
||||
## Clear your account
|
||||
@@ -39,7 +39,7 @@ There are two ways to clear your account: delete everything using the free Batch
|
||||
|
||||
After clearing your new account, please download a backup from your old account and import it into your new account while merging local data:
|
||||
|
||||
1. Open the [web app](https://app.standardnotes.org) or desktop app.
|
||||
1. Open the [web app](https://app.standardnotes.com) or desktop app.
|
||||
|
||||
2. Export an encrypted or decrypted backup from your old account via the **Account** menu at the bottom left corner of the app.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ hide_title: false
|
||||
hide_table_of_contents: false
|
||||
---
|
||||
|
||||
If you are experiencing issues with signing in to the apps, you may want to clear the app’s storage. Before proceeding, please sign in to the [web](https://app.standardnotes.org) app (in a different browser, if needed) to confirm that notes, tags, and other items on your notes syncing account that were modified or created on another device were saved and synced to our servers.
|
||||
If you are experiencing issues with signing in to the apps, you may want to clear the app’s storage. Before proceeding, please sign in to the [web](https://app.standardnotes.com) app (in a different browser, if needed) to confirm that notes, tags, and other items on your notes syncing account that were modified or created on another device were saved and synced to our servers.
|
||||
|
||||
:::warning
|
||||
If you do not have an account, do not proceed with these steps until a fix has been made available. You may have some luck in simply entering in your password or passcode several times until the app unlocks.
|
||||
@@ -25,7 +25,7 @@ If you do not have an account, do not proceed with these steps until a fix has b
|
||||
|
||||
## Mobile
|
||||
|
||||
**Please note:** Reinstalling the app on mobile devices may download a backup of your app from the cloud and you might run into the same issue again. Clearing the cache alone is usually not enough to reset the app. If you have an [account](https://app.standardnotes.org) with us and can verify that your changes have synced, then clearing the app's storage will not result in the loss of your notes.
|
||||
**Please note:** Reinstalling the app on mobile devices may download a backup of your app from the cloud and you might run into the same issue again. Clearing the cache alone is usually not enough to reset the app. If you have an [account](https://app.standardnotes.com) with us and can verify that your changes have synced, then clearing the app's storage will not result in the loss of your notes.
|
||||
|
||||
### [Android](https://play.google.com/store/apps/details?id=com.standardnotes&hl=en_US)
|
||||
|
||||
@@ -47,9 +47,9 @@ If you do not have an account, do not proceed with these steps until a fix has b
|
||||
4. From there, please reinstall the app and sign in again.
|
||||
- You can enable the setting to backup the app to iCloud again, if you would like.
|
||||
|
||||
## [Desktop](https://standardnotes.com/download) and [Web](https://app.standardnotes.org)
|
||||
## [Desktop](https://standardnotes.com/download) and [Web](https://app.standardnotes.com)
|
||||
|
||||
The methods for clearing the storage of the [desktop](https://standardnotes.com/download) and [web](https://app.standardnotes.org) apps are largely similar but require toggling the developer tools, which requires different sets of steps.
|
||||
The methods for clearing the storage of the [desktop](https://standardnotes.com/download) and [web](https://app.standardnotes.com) apps are largely similar but require toggling the developer tools, which requires different sets of steps.
|
||||
|
||||
### Desktop
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ The Action Bar is written in JavaScript and compiled with Grunt.
|
||||
1. Clone the [action-bar](https://github.com/standardnotes/action-bar) repository from GitHub.
|
||||
2. Run `npm install` to install required dependencies.
|
||||
3. Ensure that either the Standard Notes desktop app is available for use or the web app is accessible. Use both locally or with an Extended account (or the extension will not load).
|
||||
4. Follow the instructions [here](/extensions/local-setup) to setup the extension locally.
|
||||
4. Follow the instructions [here](/extensions/local-setup/) to setup the extension locally.
|
||||
- For the `area` property, use `editor-stack`
|
||||
5. Begin development! Upon making any changes to the code, run `grunt` to build the files to the `dist` folder.
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Changing the editor for a note to the Bold Editor will add `html` tags around ea
|
||||
|
||||
If you want to convert a note from HTML to plaintext, you will need to remove these tags manually or by using a separate text editor such as [VS Code](https://code.visualstudio.com/) or [Atom](https://atom.io) because we do not yet have a "find and replace" feature. If you would like to test the Bold Editor with your note, you can restore a previous copy of the note in the Session History. If you restore an old copy, then any changes made with the Bold Editor will be lost.
|
||||
|
||||
The search feature in the [Minimist editor](https://standardnotes.com/extensions/markdown-minimist) may help you remove the tags manually.
|
||||
The search feature in the [Minimist editor](https://standardnotes.com/features/markdown-minimist) may help you remove the tags manually.
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ hide_table_of_contents: false
|
||||
|
||||
## Introduction
|
||||
|
||||
You can use the [Folders](https://standardnotes.com/extensions/folders) extension to create nested folders from your tags with easy drag and drop. Folders also supports [Smart Tags](/usage/tags), which allow you to build custom filters for viewing your notes.
|
||||
You can use the [Folders](https://standardnotes.com/features/folders) extension to create nested folders from your tags with easy drag and drop. Folders also supports [Smart Tags](/usage/tags/), which allow you to build custom filters for viewing your notes.
|
||||
|
||||
## Terminology
|
||||
|
||||
@@ -29,7 +29,7 @@ Nested tags are recorded in a `Parent.Child` format and appear that way on mobil
|
||||
|
||||
If you add a child tag to a note, the tag's parent tag may or may not be added depending on how you add the child tag.
|
||||
|
||||
If you create a note in a folder (e.g., the **All** folder) and add a child tag using the [Quick Tags](/usage/tags) extension, its parent tag will also be added. If you create a note in the child folder, the child tag will automatically be added to the note, but the tag for the parent folder will not be added.
|
||||
If you create a note in a folder (e.g., the **All** folder) and add a child tag using the [Quick Tags](/usage/tags/) extension, its parent tag will also be added. If you create a note in the child folder, the child tag will automatically be added to the note, but the tag for the parent folder will not be added.
|
||||
|
||||
For example, if your **Recipes** folder includes the **Cakes** and **Pasta** tags, then there are two main ways to approach adding "Spaghetti Recipe" note to the **Pasta** folder:
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Markdown Basic is a [custom editor](https://standardnotes.com/help/77/what-are-e
|
||||
|
||||
## Installation
|
||||
|
||||
1. Register for an account at Standard Notes using the [Desktop App](https://standardnotes.com/download) or [Web app](https://app.standardnotes.org). Remember to use a strong and memorable password.
|
||||
1. Register for an account at Standard Notes using the [Desktop App](https://standardnotes.com/download) or [Web app](https://app.standardnotes.com). Remember to use a strong and memorable password.
|
||||
2. Sign up for [Standard Notes Extended](https://dashboard.standardnotes.com/member). Then, follow the instructions [here](https://standardnotes.com/help/29/how-do-i-install-extensions-once-i-ve-signed-up-for-extended) or continue.
|
||||
3. Click **Extensions** in the lower left corner.
|
||||
4. Under **Repository**, find **Markdown Basic**.
|
||||
|
||||
@@ -18,7 +18,7 @@ hide_table_of_contents: false
|
||||
|
||||
Secure Spreadsheets is a [derived editor](https://standardnotes.com/help/77/what-are-editors). It is derived from [Kendo UI Professional](https://github.com/telerik/kendo-ui-core#features-of-kendo-ui-core).
|
||||
|
||||
A demo of the Secure Spreadsheets editor is available at [standardnotes.org/demo](https://standardnotes.com/demo). To use Secure Spreadsheets with Standard Notes, please sign up for [Standard Notes Extended](https://standardnotes.com/extensions) and install it by following the instructions described [here](https://standardnotes.com/help/29/how-do-i-install-extensions-once-i-ve-signed-up-for-extended).
|
||||
A demo of the Secure Spreadsheets editor is available at [standardnotes.com/demo](https://standardnotes.com/demo). To use Secure Spreadsheets with Standard Notes, please sign up for [Standard Notes Extended](https://standardnotes.com/plans) and install it by following the instructions described [here](https://standardnotes.com/help/29/how-do-i-install-extensions-once-i-ve-signed-up-for-extended).
|
||||
|
||||
## Export
|
||||
|
||||
|
||||
@@ -20,16 +20,16 @@ This documentation explains how to get started with using Standard Notes, publis
|
||||
|
||||
## Topics
|
||||
|
||||
- [Self-hosting a Syncing Server](/self-hosting/getting-started)
|
||||
- [Developing Extensions](/extensions/intro)
|
||||
- [Client Encryption API](/specification/encryption)
|
||||
- [Self-hosting a Syncing Server](/self-hosting/getting-started/)
|
||||
- [Developing Extensions](/extensions/intro/)
|
||||
- [Client Encryption API](/specification/encryption/)
|
||||
|
||||
## Staying informed
|
||||
|
||||
- [GitHub](https://github.com/standardnotes)
|
||||
- [Discord](https://standardnotes.com/discord)
|
||||
- [Twitter](https://twitter.com/standardnotes)
|
||||
- [Blog](https://blog.standardnotes.org)
|
||||
- [Blog](https://standardnotes.com/blog)
|
||||
|
||||
## Something missing?
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/docs",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.7",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Sitemap: https://docs.standardnotes.com/sitemap
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.20.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **snjs:** add sign in with recovery codes use case ([#2130](https://github.com/standardnotes/app/issues/2130)) ([be028ff](https://github.com/standardnotes/app/commit/be028ff87bb5306fc266b70567cbea8a13547e7e))
|
||||
|
||||
## [1.19.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.19.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.19.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.19.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.19.32",
|
||||
"version": "1.20.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -32,6 +32,9 @@ export interface EncryptionProviderInterface {
|
||||
getKeyEmbeddedKeyParams(key: EncryptedPayloadInterface): SNRootKeyParams | undefined
|
||||
computeRootKey(password: string, keyParams: SNRootKeyParams): Promise<RootKeyInterface>
|
||||
supportedVersions(): ProtocolVersion[]
|
||||
isVersionNewerThanLibraryVersion(version: ProtocolVersion): boolean
|
||||
platformSupportsKeyDerivation(keyParams: SNRootKeyParams): boolean
|
||||
computeWrappingKey(passcode: string): Promise<RootKeyInterface>
|
||||
getUserVersion(): ProtocolVersion | undefined
|
||||
decryptBackupFile(
|
||||
file: BackupFile,
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.58.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
### Features
|
||||
|
||||
* Added per-tag preference to use table layout and removed "Files Table View" from Labs ([dd8ccde](https://github.com/standardnotes/app/commit/dd8ccdeadc6c2fd7f7ccd66f2dc4b0081616fb2b))
|
||||
|
||||
## [1.57.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/features",
|
||||
"version": "1.57.1",
|
||||
"version": "1.58.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -38,8 +38,6 @@ export enum FeatureIdentifier {
|
||||
TaskEditor = 'org.standardnotes.simple-task-editor',
|
||||
TokenVaultEditor = 'org.standardnotes.token-vault',
|
||||
|
||||
FilesTableView = 'org.standardnotes.files-table-view',
|
||||
|
||||
DeprecatedBoldEditor = 'org.standardnotes.bold-editor',
|
||||
DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-markdown-editor',
|
||||
DeprecatedMarkdownMathEditor = 'org.standardnotes.fancy-markdown-editor',
|
||||
@@ -53,4 +51,4 @@ export enum FeatureIdentifier {
|
||||
*/
|
||||
export const LegacyFileSafeIdentifier = 'org.standardnotes.legacy.file-safe'
|
||||
|
||||
export const ExperimentalFeatures = [FeatureIdentifier.FilesTableView]
|
||||
export const ExperimentalFeatures = []
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
import { RoleName, SubscriptionName } from '@standardnotes/common'
|
||||
import { FeatureDescription } from '../Feature/FeatureDescription'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
|
||||
export function experimentalFeatures(): FeatureDescription[] {
|
||||
const filesTableView: FeatureDescription = {
|
||||
identifier: FeatureIdentifier.FilesTableView,
|
||||
name: 'Files Table View',
|
||||
description:
|
||||
'Replaces the current Files view with a table view, with name, size, and date sort options. Requires reload to take effect.',
|
||||
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
|
||||
availableInRoles: [RoleName.PlusUser, RoleName.ProUser],
|
||||
permission_name: PermissionName.FilesTableView,
|
||||
}
|
||||
|
||||
return [filesTableView]
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -40,5 +40,4 @@ export enum PermissionName {
|
||||
TwoFactorAuth = 'server:two-factor-auth',
|
||||
SubscriptionSharing = 'server:subscription-sharing',
|
||||
SuperEditor = 'editor:super-editor',
|
||||
FilesTableView = 'app:files-table-view',
|
||||
}
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
# [1.28.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
### Features
|
||||
|
||||
* improve initial load performance on mobile ([#2126](https://github.com/standardnotes/app/issues/2126)) ([3c332a3](https://github.com/standardnotes/app/commit/3c332a35f6024c46020a1d6ac68a5df989804142))
|
||||
|
||||
## [1.27.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -18,17 +18,6 @@ export default class WebDeviceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
async getAllRawStorageKeyValues() {
|
||||
const results = []
|
||||
for (const key of Object.keys(localStorage)) {
|
||||
results.push({
|
||||
key: key,
|
||||
value: localStorage[key],
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
async setRawStorageValue(key, value) {
|
||||
localStorage.setItem(key, value)
|
||||
}
|
||||
@@ -57,7 +46,7 @@ export default class WebDeviceInterface {
|
||||
return `${this._getDatabaseKeyPrefix(identifier)}${id}`
|
||||
}
|
||||
|
||||
async getAllRawDatabasePayloads(identifier) {
|
||||
async getAllDatabaseEntries(identifier) {
|
||||
const models = []
|
||||
for (const key in localStorage) {
|
||||
if (key.startsWith(this._getDatabaseKeyPrefix(identifier))) {
|
||||
@@ -67,21 +56,21 @@ export default class WebDeviceInterface {
|
||||
return models
|
||||
}
|
||||
|
||||
async saveRawDatabasePayload(payload, identifier) {
|
||||
async saveDatabaseEntry(payload, identifier) {
|
||||
localStorage.setItem(this._keyForPayloadId(payload.uuid, identifier), JSON.stringify(payload))
|
||||
}
|
||||
|
||||
async saveRawDatabasePayloads(payloads, identifier) {
|
||||
async saveDatabaseEntries(payloads, identifier) {
|
||||
for (const payload of payloads) {
|
||||
await this.saveRawDatabasePayload(payload, identifier)
|
||||
await this.saveDatabaseEntry(payload, identifier)
|
||||
}
|
||||
}
|
||||
|
||||
async removeRawDatabasePayloadWithId(id, identifier) {
|
||||
async removeDatabaseEntry(id, identifier) {
|
||||
localStorage.removeItem(this._keyForPayloadId(id, identifier))
|
||||
}
|
||||
|
||||
async removeAllRawDatabasePayloads(identifier) {
|
||||
async removeAllDatabaseEntries(identifier) {
|
||||
for (const key in localStorage) {
|
||||
if (key.startsWith(this._getDatabaseKeyPrefix(identifier))) {
|
||||
delete localStorage[key]
|
||||
@@ -121,12 +110,6 @@ export default class WebDeviceInterface {
|
||||
localStorage.setItem(KEYCHAIN_STORAGE_KEY, JSON.stringify(keychain))
|
||||
}
|
||||
|
||||
/** Allows unit tests to set legacy keychain structure as it was <= 003 */
|
||||
// eslint-disable-next-line camelcase
|
||||
async setLegacyRawKeychainValue(value) {
|
||||
localStorage.setItem(KEYCHAIN_STORAGE_KEY, JSON.stringify(value))
|
||||
}
|
||||
|
||||
async getRawKeychainValue() {
|
||||
const keychain = localStorage.getItem(KEYCHAIN_STORAGE_KEY)
|
||||
return JSON.parse(keychain)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.27.10",
|
||||
"version": "1.28.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.14.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.14.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.14.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.14.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.14.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.14.9",
|
||||
"version": "1.14.13",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,72 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.50.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.50.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
# [3.50.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
### Features
|
||||
|
||||
* improve initial load performance on mobile ([#2126](https://github.com/standardnotes/app/issues/2126)) ([3c332a3](https://github.com/standardnotes/app/commit/3c332a35f6024c46020a1d6ac68a5df989804142))
|
||||
|
||||
## [3.49.60](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
for_platform :ios do
|
||||
for_lane :dev do
|
||||
app_identifier "com.standardnotes.standardnotes.dev"
|
||||
end
|
||||
for_lane :prod do
|
||||
app_identifier "com.standardnotes.standardnotes"
|
||||
end
|
||||
end
|
||||
|
||||
for_platform :android do
|
||||
for_lane :dev do
|
||||
package_name 'com.standardnotes.dev'
|
||||
end
|
||||
for_lane :prod do
|
||||
package_name 'com.standardnotes'
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ storage_mode("git")
|
||||
|
||||
# type("development") # The default type, can be: appstore, adhoc, enterprise or development
|
||||
|
||||
app_identifier(["com.standardnotes.standardnotes", "com.standardnotes.standardnotes.dev"])
|
||||
app_identifier(["com.standardnotes.standardnotes"])
|
||||
|
||||
# For all available options run `fastlane match --help`
|
||||
# Remove the # in the beginning of the line to enable the other options
|
||||
|
||||
@@ -75,6 +75,9 @@ PODS:
|
||||
- glog (0.3.5)
|
||||
- hermes-engine (0.70.6)
|
||||
- libevent (2.1.12)
|
||||
- MMKV (1.2.14):
|
||||
- MMKVCore (~> 1.2.14)
|
||||
- MMKVCore (1.2.14)
|
||||
- OpenSSL-Universal (1.1.1100)
|
||||
- RCT-Folly (2021.07.22.00):
|
||||
- boost
|
||||
@@ -304,6 +307,9 @@ PODS:
|
||||
- glog
|
||||
- react-native-fingerprint-scanner (5.0.0):
|
||||
- React-Core
|
||||
- react-native-mmkv (2.5.1):
|
||||
- MMKV (>= 1.2.13)
|
||||
- React-Core
|
||||
- react-native-version-info (1.1.1):
|
||||
- React-Core
|
||||
- react-native-webview (11.23.1):
|
||||
@@ -444,6 +450,7 @@ DEPENDENCIES:
|
||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
||||
- react-native-fingerprint-scanner (from `../node_modules/react-native-fingerprint-scanner`)
|
||||
- react-native-mmkv (from `../node_modules/react-native-mmkv`)
|
||||
- react-native-version-info (from `../node_modules/react-native-version-info`)
|
||||
- react-native-webview (from `../node_modules/react-native-webview`)
|
||||
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
@@ -483,6 +490,8 @@ SPEC REPOS:
|
||||
- FlipperKit
|
||||
- fmt
|
||||
- libevent
|
||||
- MMKV
|
||||
- MMKVCore
|
||||
- OpenSSL-Universal
|
||||
- SocketRocket
|
||||
- TrustKit
|
||||
@@ -533,6 +542,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon/logger"
|
||||
react-native-fingerprint-scanner:
|
||||
:path: "../node_modules/react-native-fingerprint-scanner"
|
||||
react-native-mmkv:
|
||||
:path: "../node_modules/react-native-mmkv"
|
||||
react-native-version-info:
|
||||
:path: "../node_modules/react-native-version-info"
|
||||
react-native-webview:
|
||||
@@ -583,7 +594,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
FBLazyVector: 48289402952f4f7a4e235de70a9a590aa0b79ef4
|
||||
FBReactNativeSpec: dd1186fd05255e3457baa2f4ca65e94c2cd1e3ac
|
||||
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
|
||||
@@ -596,9 +607,11 @@ SPEC CHECKSUMS:
|
||||
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
||||
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 85ecdd10ee8d8ec362ef519a6a45ff9aa27b2e85
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
MMKV: 9c4663aa7ca255d478ff10f2f5cb7d17c1651ccd
|
||||
MMKVCore: 89f5c8a66bba2dcd551779dea4d412eeec8ff5bb
|
||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
|
||||
RCTRequired: e1866f61af7049eb3d8e08e8b133abd38bc1ca7a
|
||||
@@ -616,6 +629,7 @@ SPEC CHECKSUMS:
|
||||
React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b
|
||||
React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0
|
||||
react-native-fingerprint-scanner: be63e626b31fb951780a5fac5328b065a61a3d6e
|
||||
react-native-mmkv: 69b9c003f10afdd01addf7c6ee784ce42ee2eff3
|
||||
react-native-version-info: a106f23009ac0db4ee00de39574eb546682579b9
|
||||
react-native-webview: d33e2db8925d090871ffeb232dfa50cb3a727581
|
||||
React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Photo library is optionally used to select files to upload or QR code images from your photo library.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Microphone is optionally used to capture videos.</string>
|
||||
<string>Microphone is optionally used to capture videos.</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>AntDesign.ttf</string>
|
||||
@@ -147,5 +147,7 @@
|
||||
<false/>
|
||||
<key>supportsAlternateIcons</key>
|
||||
<true/>
|
||||
<key>RCTAsyncStorageExcludeFromBackup</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.49.60",
|
||||
"version": "3.50.15",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
@@ -59,6 +59,7 @@
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-iap": "^12.4.4",
|
||||
"react-native-keychain": "standardnotes/react-native-keychain#d277d360494cbd02be4accb4a360772a8e0e97b6",
|
||||
"react-native-mmkv": "^2.5.1",
|
||||
"react-native-privacy-snapshot": "standardnotes/react-native-privacy-snapshot#653e904c90fc6f2b578da59138f2bfe5d7f942fe",
|
||||
"react-native-share": "^8.0.0",
|
||||
"react-native-version-info": "^1.1.1",
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
import AsyncStorage from '@react-native-community/async-storage'
|
||||
import {
|
||||
DatabaseKeysLoadChunk,
|
||||
DatabaseKeysLoadChunkResponse,
|
||||
DatabaseLoadOptions,
|
||||
GetSortedPayloadsByPriority,
|
||||
TransferPayload,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Platform } from 'react-native'
|
||||
import { DatabaseInterface } from './DatabaseInterface'
|
||||
import { DatabaseMetadata } from './DatabaseMetadata'
|
||||
import { FlashKeyValueStore } from './FlashKeyValueStore'
|
||||
import { isLegacyIdentifier } from './LegacyIdentifier'
|
||||
import { showLoadFailForItemIds } from './showLoadFailForItemIds'
|
||||
|
||||
export class Database implements DatabaseInterface {
|
||||
private metadataStore: DatabaseMetadata
|
||||
|
||||
constructor(private identifier: string) {
|
||||
const flashStorage = new FlashKeyValueStore(identifier)
|
||||
this.metadataStore = new DatabaseMetadata(identifier, flashStorage)
|
||||
}
|
||||
|
||||
private databaseKeyForPayloadId(id: string) {
|
||||
return `${this.getDatabaseKeyPrefix()}${id}`
|
||||
}
|
||||
|
||||
private getDatabaseKeyPrefix() {
|
||||
if (this.identifier && !isLegacyIdentifier(this.identifier)) {
|
||||
return `${this.identifier}-Item-`
|
||||
} else {
|
||||
return 'Item-'
|
||||
}
|
||||
}
|
||||
|
||||
async getAllEntries<T extends TransferPayload = TransferPayload>(): Promise<T[]> {
|
||||
const keys = await this.getAllKeys()
|
||||
return this.multiGet(keys)
|
||||
}
|
||||
|
||||
async getAllKeys(): Promise<string[]> {
|
||||
const keys = await AsyncStorage.getAllKeys()
|
||||
const filtered = keys.filter((key) => {
|
||||
return key.startsWith(this.getDatabaseKeyPrefix())
|
||||
})
|
||||
return filtered
|
||||
}
|
||||
|
||||
async multiDelete(keys: string[]): Promise<void> {
|
||||
return AsyncStorage.multiRemove(keys)
|
||||
}
|
||||
|
||||
async deleteItem(itemUuid: string): Promise<void> {
|
||||
const key = this.databaseKeyForPayloadId(itemUuid)
|
||||
this.metadataStore.deleteMetadataItem(itemUuid)
|
||||
return this.multiDelete([key])
|
||||
}
|
||||
|
||||
async deleteAll(): Promise<void> {
|
||||
const keys = await this.getAllKeys()
|
||||
return this.multiDelete(keys)
|
||||
}
|
||||
|
||||
async setItems(items: TransferPayload[]): Promise<void> {
|
||||
if (items.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
items.map((item) => {
|
||||
return Promise.all([
|
||||
AsyncStorage.setItem(this.databaseKeyForPayloadId(item.uuid), JSON.stringify(item)),
|
||||
this.metadataStore.setMetadataForPayloads([item]),
|
||||
])
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async getLoadChunks(options: DatabaseLoadOptions): Promise<DatabaseKeysLoadChunkResponse> {
|
||||
let metadataItems = this.metadataStore.getAllMetadataItems()
|
||||
|
||||
if (metadataItems.length === 0) {
|
||||
const allEntries = await this.getAllEntries()
|
||||
metadataItems = this.metadataStore.runMigration(allEntries)
|
||||
}
|
||||
|
||||
const sorted = GetSortedPayloadsByPriority(metadataItems, options)
|
||||
|
||||
const itemsKeysChunk: DatabaseKeysLoadChunk = {
|
||||
keys: sorted.itemsKeyPayloads.map((item) => this.databaseKeyForPayloadId(item.uuid)),
|
||||
}
|
||||
|
||||
const contentTypePriorityChunk: DatabaseKeysLoadChunk = {
|
||||
keys: sorted.contentTypePriorityPayloads.map((item) => this.databaseKeyForPayloadId(item.uuid)),
|
||||
}
|
||||
|
||||
const remainingKeys = sorted.remainingPayloads.map((item) => this.databaseKeyForPayloadId(item.uuid))
|
||||
|
||||
const remainingKeysChunks: DatabaseKeysLoadChunk[] = []
|
||||
for (let i = 0; i < remainingKeys.length; i += options.batchSize) {
|
||||
remainingKeysChunks.push({
|
||||
keys: remainingKeys.slice(i, i + options.batchSize),
|
||||
})
|
||||
}
|
||||
|
||||
const result: DatabaseKeysLoadChunkResponse = {
|
||||
keys: {
|
||||
itemsKeys: itemsKeysChunk,
|
||||
remainingChunks: [contentTypePriorityChunk, ...remainingKeysChunks],
|
||||
},
|
||||
remainingChunksItemCount: sorted.contentTypePriorityPayloads.length + sorted.remainingPayloads.length,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async multiGet<T>(keys: string[]): Promise<T[]> {
|
||||
const results: T[] = []
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
const failedItemIds: string[] = []
|
||||
for (const key of keys) {
|
||||
try {
|
||||
const item = await AsyncStorage.getItem(key)
|
||||
if (item) {
|
||||
try {
|
||||
results.push(JSON.parse(item) as T)
|
||||
} catch (e) {
|
||||
results.push(item as T)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error getting item', key, e)
|
||||
failedItemIds.push(key)
|
||||
}
|
||||
}
|
||||
if (failedItemIds.length > 0) {
|
||||
showLoadFailForItemIds(failedItemIds)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
for (const item of await AsyncStorage.multiGet(keys)) {
|
||||
if (item[1]) {
|
||||
try {
|
||||
results.push(JSON.parse(item[1]))
|
||||
} catch (e) {
|
||||
results.push(item[1] as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error getting items', e)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { TransferPayload } from '@standardnotes/snjs'
|
||||
|
||||
export interface DatabaseInterface {
|
||||
getAllKeys(): Promise<string[]>
|
||||
multiDelete(keys: string[]): Promise<void>
|
||||
deleteItem(itemUuid: string): Promise<void>
|
||||
deleteAll(): Promise<void>
|
||||
setItems(items: TransferPayload[]): Promise<void>
|
||||
multiGet<T>(keys: string[]): Promise<T[]>
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { DatabaseItemMetadata, isNotUndefined, TransferPayload } from '@standardnotes/snjs'
|
||||
import { FlashKeyValueStore } from './FlashKeyValueStore'
|
||||
|
||||
export class DatabaseMetadata {
|
||||
constructor(private identifier: string, private flashStorage: FlashKeyValueStore) {}
|
||||
|
||||
runMigration(payloads: TransferPayload[]) {
|
||||
const metadataItems = this.setMetadataForPayloads(payloads)
|
||||
return metadataItems
|
||||
}
|
||||
|
||||
setMetadataForPayloads(payloads: TransferPayload[]) {
|
||||
const metadataItems = []
|
||||
for (const payload of payloads) {
|
||||
const { uuid, content_type, updated_at } = payload
|
||||
const key = this.keyForUuid(uuid)
|
||||
const metadata: DatabaseItemMetadata = { uuid, content_type, updated_at }
|
||||
this.flashStorage.set(key, metadata)
|
||||
metadataItems.push(metadata)
|
||||
}
|
||||
return metadataItems
|
||||
}
|
||||
|
||||
deleteMetadataItem(itemUuid: string) {
|
||||
const key = this.keyForUuid(itemUuid)
|
||||
this.flashStorage.delete(key)
|
||||
}
|
||||
|
||||
getAllMetadataItems(): DatabaseItemMetadata[] {
|
||||
const keys = this.flashStorage.getAllKeys()
|
||||
const metadataKeys = keys.filter((key) => key.endsWith('-Metadata'))
|
||||
const metadataItems = this.flashStorage.multiGet<DatabaseItemMetadata>(metadataKeys).filter(isNotUndefined)
|
||||
return metadataItems
|
||||
}
|
||||
|
||||
private keyForUuid(uuid: string) {
|
||||
return `${this.identifier}-Item-${uuid}-Metadata`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { MMKV } from 'react-native-mmkv'
|
||||
|
||||
export class FlashKeyValueStore {
|
||||
private storage: MMKV
|
||||
|
||||
constructor(identifier: string) {
|
||||
this.storage = new MMKV({ id: identifier })
|
||||
}
|
||||
|
||||
set(key: string, value: unknown): void {
|
||||
this.storage.set(key, JSON.stringify(value))
|
||||
}
|
||||
|
||||
delete(key: string): void {
|
||||
this.storage.delete(key)
|
||||
}
|
||||
|
||||
deleteAll(): void {
|
||||
this.storage.clearAll()
|
||||
}
|
||||
|
||||
getAllKeys(): string[] {
|
||||
return this.storage.getAllKeys()
|
||||
}
|
||||
|
||||
get<T>(key: string): T | undefined {
|
||||
const item = this.storage.getString(key)
|
||||
if (item) {
|
||||
try {
|
||||
return JSON.parse(item)
|
||||
} catch (e) {
|
||||
return item as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiGet<T>(keys: string[]): (T | undefined)[] {
|
||||
return keys.map((key) => this.get<T>(key))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { ApplicationIdentifier } from '@standardnotes/snjs'
|
||||
|
||||
/**
|
||||
* This identifier was the database name used in Standard Notes web/desktop.
|
||||
*/
|
||||
const LEGACY_IDENTIFIER = 'standardnotes'
|
||||
|
||||
/**
|
||||
* We use this function to decide if we need to prefix the identifier in getDatabaseKeyPrefix or not.
|
||||
* It is also used to decide if the raw or the namespaced keychain is used.
|
||||
* @param identifier The ApplicationIdentifier
|
||||
*/
|
||||
export const isLegacyIdentifier = function (identifier: ApplicationIdentifier) {
|
||||
return identifier && identifier === LEGACY_IDENTIFIER
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import AsyncStorage from '@react-native-community/async-storage'
|
||||
|
||||
export class LegacyKeyValueStore {
|
||||
set(key: string, value: string): Promise<void> {
|
||||
return AsyncStorage.setItem(key, JSON.stringify(value))
|
||||
}
|
||||
|
||||
delete(key: string): Promise<void> {
|
||||
return AsyncStorage.removeItem(key)
|
||||
}
|
||||
|
||||
deleteAll(): Promise<void> {
|
||||
return AsyncStorage.clear()
|
||||
}
|
||||
|
||||
async getValue<T>(key: string): Promise<T | undefined> {
|
||||
const item = await AsyncStorage.getItem(key)
|
||||
if (item) {
|
||||
try {
|
||||
return JSON.parse(item)
|
||||
} catch (e) {
|
||||
return item as T
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Alert } from 'react-native'
|
||||
|
||||
export const showLoadFailForItemIds = (failedItemIds: string[]) => {
|
||||
let text =
|
||||
'The following items could not be loaded. This may happen if you are in low-memory conditions, or if the note is very large in size. We recommend breaking up large notes into smaller chunks using the desktop or web app.\n\nItems:\n'
|
||||
let index = 0
|
||||
text += failedItemIds.map((id) => {
|
||||
let result = id
|
||||
if (index !== failedItemIds.length - 1) {
|
||||
result += '\n'
|
||||
}
|
||||
index++
|
||||
return result
|
||||
})
|
||||
Alert.alert('Unable to load item(s)', text)
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
import AsyncStorage from '@react-native-community/async-storage'
|
||||
import SNReactNative from '@standardnotes/react-native-utils'
|
||||
import { AppleIAPReceipt } from '@standardnotes/services'
|
||||
import {
|
||||
AppleIAPProductId,
|
||||
AppleIAPReceipt,
|
||||
ApplicationIdentifier,
|
||||
DatabaseKeysLoadChunkResponse,
|
||||
DatabaseLoadOptions,
|
||||
Environment,
|
||||
LegacyMobileKeychainStructure,
|
||||
LegacyRawKeychainValue,
|
||||
MobileDeviceInterface,
|
||||
NamespacedRootKeyInKeychain,
|
||||
Platform as SNPlatform,
|
||||
@@ -41,8 +40,11 @@ import {
|
||||
import { hide, show } from 'react-native-privacy-snapshot'
|
||||
import Share from 'react-native-share'
|
||||
import { AndroidBackHandlerService } from '../AndroidBackHandlerService'
|
||||
import { AppStateObserverService } from '../AppStateObserverService'
|
||||
import { PurchaseManager } from '../PurchaseManager'
|
||||
import { AppStateObserverService } from './../AppStateObserverService'
|
||||
import { Database } from './Database/Database'
|
||||
import { isLegacyIdentifier } from './Database/LegacyIdentifier'
|
||||
import { LegacyKeyValueStore } from './Database/LegacyKeyValueStore'
|
||||
import Keychain from './Keychain'
|
||||
|
||||
export type BiometricsType = 'Fingerprint' | 'Face ID' | 'Biometrics' | 'Touch ID'
|
||||
@@ -53,41 +55,6 @@ export enum MobileDeviceEvent {
|
||||
|
||||
type MobileDeviceEventHandler = (event: MobileDeviceEvent) => void
|
||||
|
||||
/**
|
||||
* This identifier was the database name used in Standard Notes web/desktop.
|
||||
*/
|
||||
const LEGACY_IDENTIFIER = 'standardnotes'
|
||||
|
||||
/**
|
||||
* We use this function to decide if we need to prefix the identifier in getDatabaseKeyPrefix or not.
|
||||
* It is also used to decide if the raw or the namespaced keychain is used.
|
||||
* @param identifier The ApplicationIdentifier
|
||||
*/
|
||||
const isLegacyIdentifier = function (identifier: ApplicationIdentifier) {
|
||||
return identifier && identifier === LEGACY_IDENTIFIER
|
||||
}
|
||||
|
||||
function isLegacyMobileKeychain(
|
||||
x: LegacyMobileKeychainStructure | RawKeychainValue,
|
||||
): x is LegacyMobileKeychainStructure {
|
||||
return x.ak != undefined
|
||||
}
|
||||
|
||||
const showLoadFailForItemIds = (failedItemIds: string[]) => {
|
||||
let text =
|
||||
'The following items could not be loaded. This may happen if you are in low-memory conditions, or if the note is very large in size. We recommend breaking up large notes into smaller chunks using the desktop or web app.\n\nItems:\n'
|
||||
let index = 0
|
||||
text += failedItemIds.map((id) => {
|
||||
let result = id
|
||||
if (index !== failedItemIds.length - 1) {
|
||||
result += '\n'
|
||||
}
|
||||
index++
|
||||
return result
|
||||
})
|
||||
Alert.alert('Unable to load item(s)', text)
|
||||
}
|
||||
|
||||
export class MobileDevice implements MobileDeviceInterface {
|
||||
environment: Environment.Mobile = Environment.Mobile
|
||||
platform: SNPlatform.Ios | SNPlatform.Android = Platform.OS === 'ios' ? SNPlatform.Ios : SNPlatform.Android
|
||||
@@ -95,6 +62,8 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
public isDarkMode = false
|
||||
public statusBarBgColor: string | undefined
|
||||
private componentUrls: Map<UuidString, string> = new Map()
|
||||
private keyValueStore = new LegacyKeyValueStore()
|
||||
private databases = new Map<string, Database>()
|
||||
|
||||
constructor(
|
||||
private stateObserverService?: AppStateObserverService,
|
||||
@@ -106,6 +75,17 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
return PurchaseManager.getInstance().purchase(plan)
|
||||
}
|
||||
|
||||
private findOrCreateDatabase(identifier: ApplicationIdentifier): Database {
|
||||
const existing = this.databases.get(identifier)
|
||||
if (existing) {
|
||||
return existing
|
||||
}
|
||||
|
||||
const newDb = new Database(identifier)
|
||||
this.databases.set(identifier, newDb)
|
||||
return newDb
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.stateObserverService?.deinit()
|
||||
;(this.stateObserverService as unknown) = undefined
|
||||
@@ -120,10 +100,6 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
console.log(args)
|
||||
}
|
||||
|
||||
async setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void> {
|
||||
await Keychain.setKeys(value)
|
||||
}
|
||||
|
||||
public async getJsonParsedRawStorageValue(key: string): Promise<unknown | undefined> {
|
||||
const value = await this.getRawStorageValue(key)
|
||||
if (value == undefined) {
|
||||
@@ -136,219 +112,57 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
private getDatabaseKeyPrefix(identifier: ApplicationIdentifier) {
|
||||
if (identifier && !isLegacyIdentifier(identifier)) {
|
||||
return `${identifier}-Item-`
|
||||
} else {
|
||||
return 'Item-'
|
||||
}
|
||||
}
|
||||
|
||||
private keyForPayloadId(id: string, identifier: ApplicationIdentifier) {
|
||||
return `${this.getDatabaseKeyPrefix(identifier)}${id}`
|
||||
}
|
||||
|
||||
private async getAllDatabaseKeys(identifier: ApplicationIdentifier) {
|
||||
const keys = await AsyncStorage.getAllKeys()
|
||||
const filtered = keys.filter((key) => {
|
||||
return key.startsWith(this.getDatabaseKeyPrefix(identifier))
|
||||
})
|
||||
return filtered
|
||||
}
|
||||
|
||||
getDatabaseKeys(): Promise<string[]> {
|
||||
return AsyncStorage.getAllKeys()
|
||||
}
|
||||
|
||||
private async getRawStorageKeyValues(keys: string[]) {
|
||||
const results: { key: string; value: unknown }[] = []
|
||||
if (Platform.OS === 'android') {
|
||||
for (const key of keys) {
|
||||
try {
|
||||
const item = await AsyncStorage.getItem(key)
|
||||
if (item) {
|
||||
results.push({ key, value: item })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error getting item', key, e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
for (const item of await AsyncStorage.multiGet(keys)) {
|
||||
if (item[1]) {
|
||||
results.push({ key: item[0], value: item[1] })
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error getting items', e)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
private async getDatabaseKeyValues(keys: string[]) {
|
||||
const results: (TransferPayload | unknown)[] = []
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
const failedItemIds: string[] = []
|
||||
for (const key of keys) {
|
||||
try {
|
||||
const item = await AsyncStorage.getItem(key)
|
||||
if (item) {
|
||||
try {
|
||||
results.push(JSON.parse(item) as TransferPayload)
|
||||
} catch (e) {
|
||||
results.push(item)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error getting item', key, e)
|
||||
failedItemIds.push(key)
|
||||
}
|
||||
}
|
||||
if (failedItemIds.length > 0) {
|
||||
showLoadFailForItemIds(failedItemIds)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
for (const item of await AsyncStorage.multiGet(keys)) {
|
||||
if (item[1]) {
|
||||
try {
|
||||
results.push(JSON.parse(item[1]))
|
||||
} catch (e) {
|
||||
results.push(item[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error getting items', e)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
async getRawStorageValue(key: string) {
|
||||
const item = await AsyncStorage.getItem(key)
|
||||
if (item) {
|
||||
try {
|
||||
return JSON.parse(item)
|
||||
} catch (e) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hideMobileInterfaceFromScreenshots(): void {
|
||||
hide()
|
||||
this.setAndroidScreenshotPrivacy(true)
|
||||
}
|
||||
|
||||
stopHidingMobileInterfaceFromScreenshots(): void {
|
||||
show()
|
||||
this.setAndroidScreenshotPrivacy(false)
|
||||
}
|
||||
|
||||
async getAllRawStorageKeyValues() {
|
||||
const keys = await AsyncStorage.getAllKeys()
|
||||
return this.getRawStorageKeyValues(keys)
|
||||
getRawStorageValue(key: string): Promise<string | undefined> {
|
||||
return this.keyValueStore.getValue(key)
|
||||
}
|
||||
|
||||
setRawStorageValue(key: string, value: string): Promise<void> {
|
||||
return AsyncStorage.setItem(key, JSON.stringify(value))
|
||||
return this.keyValueStore.set(key, value)
|
||||
}
|
||||
|
||||
removeRawStorageValue(key: string): Promise<void> {
|
||||
return AsyncStorage.removeItem(key)
|
||||
return this.keyValueStore.delete(key)
|
||||
}
|
||||
|
||||
removeAllRawStorageValues(): Promise<void> {
|
||||
return AsyncStorage.clear()
|
||||
return this.keyValueStore.deleteAll()
|
||||
}
|
||||
|
||||
openDatabase(): Promise<{ isNewDatabase?: boolean | undefined } | undefined> {
|
||||
return Promise.resolve({ isNewDatabase: false })
|
||||
}
|
||||
|
||||
async getAllRawDatabasePayloads<T extends TransferPayload = TransferPayload>(
|
||||
getDatabaseLoadChunks(options: DatabaseLoadOptions, identifier: string): Promise<DatabaseKeysLoadChunkResponse> {
|
||||
return this.findOrCreateDatabase(identifier).getLoadChunks(options)
|
||||
}
|
||||
|
||||
async getAllDatabaseEntries<T extends TransferPayload = TransferPayload>(
|
||||
identifier: ApplicationIdentifier,
|
||||
): Promise<T[]> {
|
||||
const keys = await this.getAllDatabaseKeys(identifier)
|
||||
return this.getDatabaseKeyValues(keys) as Promise<T[]>
|
||||
return this.findOrCreateDatabase(identifier).getAllEntries()
|
||||
}
|
||||
|
||||
saveRawDatabasePayload(payload: TransferPayload, identifier: ApplicationIdentifier): Promise<void> {
|
||||
return this.saveRawDatabasePayloads([payload], identifier)
|
||||
}
|
||||
|
||||
async saveRawDatabasePayloads(payloads: TransferPayload[], identifier: ApplicationIdentifier): Promise<void> {
|
||||
if (payloads.length === 0) {
|
||||
return
|
||||
}
|
||||
await Promise.all(
|
||||
payloads.map((item) => {
|
||||
return AsyncStorage.setItem(this.keyForPayloadId(item.uuid, identifier), JSON.stringify(item))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier): Promise<void> {
|
||||
return this.removeRawStorageValue(this.keyForPayloadId(id, identifier))
|
||||
}
|
||||
|
||||
async removeAllRawDatabasePayloads(identifier: ApplicationIdentifier): Promise<void> {
|
||||
const keys = await this.getAllDatabaseKeys(identifier)
|
||||
return AsyncStorage.multiRemove(keys)
|
||||
}
|
||||
|
||||
async getNamespacedKeychainValue(
|
||||
async getDatabaseEntries<T extends TransferPayload = TransferPayload>(
|
||||
identifier: ApplicationIdentifier,
|
||||
): Promise<NamespacedRootKeyInKeychain | undefined> {
|
||||
const keychain = await this.getRawKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
return
|
||||
}
|
||||
|
||||
const namespacedValue = keychain[identifier]
|
||||
|
||||
if (!namespacedValue && isLegacyIdentifier(identifier)) {
|
||||
return keychain as unknown as NamespacedRootKeyInKeychain
|
||||
}
|
||||
|
||||
return namespacedValue
|
||||
keys: string[],
|
||||
): Promise<T[]> {
|
||||
return this.findOrCreateDatabase(identifier).multiGet<T>(keys)
|
||||
}
|
||||
|
||||
async setNamespacedKeychainValue(
|
||||
value: NamespacedRootKeyInKeychain,
|
||||
identifier: ApplicationIdentifier,
|
||||
): Promise<void> {
|
||||
let keychain = await this.getRawKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
keychain = {}
|
||||
}
|
||||
|
||||
await Keychain.setKeys({
|
||||
...keychain,
|
||||
[identifier]: value,
|
||||
})
|
||||
saveDatabaseEntry(payload: TransferPayload, identifier: ApplicationIdentifier): Promise<void> {
|
||||
return this.saveDatabaseEntries([payload], identifier)
|
||||
}
|
||||
|
||||
async clearNamespacedKeychainValue(identifier: ApplicationIdentifier): Promise<void> {
|
||||
const keychain = await this.getRawKeychainValue()
|
||||
async saveDatabaseEntries(payloads: TransferPayload[], identifier: ApplicationIdentifier): Promise<void> {
|
||||
return this.findOrCreateDatabase(identifier).setItems(payloads)
|
||||
}
|
||||
|
||||
if (!keychain) {
|
||||
return
|
||||
}
|
||||
removeDatabaseEntry(id: string, identifier: ApplicationIdentifier): Promise<void> {
|
||||
return this.findOrCreateDatabase(identifier).deleteItem(id)
|
||||
}
|
||||
|
||||
if (!keychain[identifier] && isLegacyIdentifier(identifier) && isLegacyMobileKeychain(keychain)) {
|
||||
await this.clearRawKeychainValue()
|
||||
return
|
||||
}
|
||||
|
||||
delete keychain[identifier]
|
||||
await Keychain.setKeys(keychain)
|
||||
async removeAllDatabaseEntries(identifier: ApplicationIdentifier): Promise<void> {
|
||||
return this.findOrCreateDatabase(identifier).deleteAll()
|
||||
}
|
||||
|
||||
async getDeviceBiometricsAvailability() {
|
||||
@@ -413,6 +227,51 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
return result
|
||||
}
|
||||
|
||||
async getNamespacedKeychainValue(
|
||||
identifier: ApplicationIdentifier,
|
||||
): Promise<NamespacedRootKeyInKeychain | undefined> {
|
||||
const keychain = await this.getRawKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
return
|
||||
}
|
||||
|
||||
const namespacedValue = keychain[identifier]
|
||||
|
||||
if (!namespacedValue && isLegacyIdentifier(identifier)) {
|
||||
return keychain as unknown as NamespacedRootKeyInKeychain
|
||||
}
|
||||
|
||||
return namespacedValue
|
||||
}
|
||||
|
||||
async setNamespacedKeychainValue(
|
||||
value: NamespacedRootKeyInKeychain,
|
||||
identifier: ApplicationIdentifier,
|
||||
): Promise<void> {
|
||||
let keychain = await this.getRawKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
keychain = {}
|
||||
}
|
||||
|
||||
await Keychain.setKeys({
|
||||
...keychain,
|
||||
[identifier]: value,
|
||||
})
|
||||
}
|
||||
|
||||
async clearNamespacedKeychainValue(identifier: ApplicationIdentifier): Promise<void> {
|
||||
const keychain = await this.getRawKeychainValue()
|
||||
|
||||
if (!keychain) {
|
||||
return
|
||||
}
|
||||
|
||||
delete keychain[identifier]
|
||||
await Keychain.setKeys(keychain)
|
||||
}
|
||||
|
||||
async getRawKeychainValue(): Promise<RawKeychainValue | undefined> {
|
||||
const result = await Keychain.getKeys()
|
||||
|
||||
@@ -641,4 +500,14 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
async getColorScheme(): Promise<ColorSchemeName> {
|
||||
return Appearance.getColorScheme()
|
||||
}
|
||||
|
||||
hideMobileInterfaceFromScreenshots(): void {
|
||||
hide()
|
||||
this.setAndroidScreenshotPrivacy(true)
|
||||
}
|
||||
|
||||
stopHidingMobileInterfaceFromScreenshots(): void {
|
||||
show()
|
||||
this.setAndroidScreenshotPrivacy(false)
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { OnShouldStartLoadWithRequest } from 'react-native-webview/lib/WebViewTy
|
||||
import { AndroidBackHandlerService } from './AndroidBackHandlerService'
|
||||
import { AppStateObserverService } from './AppStateObserverService'
|
||||
import { ColorSchemeObserverService } from './ColorSchemeObserverService'
|
||||
import { MobileDevice, MobileDeviceEvent } from './Lib/Interface'
|
||||
import { MobileDevice, MobileDeviceEvent } from './Lib/MobileDevice'
|
||||
import { IsDev } from './Lib/Utils'
|
||||
|
||||
const LoggingEnabled = IsDev
|
||||
@@ -177,6 +177,10 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
window.ReactNativeWebView.postMessage('[web log] ' + args.join(' '));
|
||||
}
|
||||
|
||||
console.error = (...args) => {
|
||||
window.ReactNativeWebView.postMessage('[web log] ' + args.join(' '));
|
||||
}
|
||||
|
||||
${WebProcessDeviceInterface}
|
||||
${WebProcessMessageSender}
|
||||
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.42.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
### Features
|
||||
|
||||
* Added per-tag preference to use table layout and removed "Files Table View" from Labs ([dd8ccde](https://github.com/standardnotes/app/commit/dd8ccdeadc6c2fd7f7ccd66f2dc4b0081616fb2b))
|
||||
|
||||
## [1.41.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
# [1.41.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
### Features
|
||||
|
||||
* improve initial load performance on mobile ([#2126](https://github.com/standardnotes/app/issues/2126)) ([3c332a3](https://github.com/standardnotes/app/commit/3c332a35f6024c46020a1d6ac68a5df989804142))
|
||||
|
||||
## [1.40.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.40.4",
|
||||
"version": "1.42.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -10,22 +10,3 @@ export interface NamespacedRootKeyInKeychain {
|
||||
}
|
||||
|
||||
export type RootKeyContentInStorage = RootKeyContentSpecialized
|
||||
|
||||
export interface LegacyRawKeychainValue {
|
||||
mk: string
|
||||
ak: string
|
||||
version: ProtocolVersion
|
||||
}
|
||||
|
||||
export type LegacyMobileKeychainStructure = {
|
||||
offline?: {
|
||||
timing?: unknown
|
||||
pw?: string
|
||||
}
|
||||
encryptedAccountKeys?: unknown
|
||||
mk: string
|
||||
pw: string
|
||||
ak: string
|
||||
version?: string
|
||||
jwt?: string
|
||||
}
|
||||
|
||||
@@ -18,4 +18,5 @@ export interface TagPreferences {
|
||||
editorIdentifier?: EditorIdentifier
|
||||
entryMode?: 'normal' | 'daily'
|
||||
panelWidth?: number
|
||||
useTableView?: boolean
|
||||
}
|
||||
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.102](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.101](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.100](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.99](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.98](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.97](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.96](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.95](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.89](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.88](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.87](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.86](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.4.86",
|
||||
"version": "1.4.102",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -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.12.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.12.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.12.12",
|
||||
"version": "1.12.13",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,34 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.53.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.53.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
# [1.53.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **snjs:** add sign in with recovery codes use case ([#2130](https://github.com/standardnotes/app/issues/2130)) ([be028ff](https://github.com/standardnotes/app/commit/be028ff87bb5306fc266b70567cbea8a13547e7e))
|
||||
|
||||
## [1.52.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.52.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
# [1.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
### Features
|
||||
|
||||
* improve initial load performance on mobile ([#2126](https://github.com/standardnotes/app/issues/2126)) ([3c332a3](https://github.com/standardnotes/app/commit/3c332a35f6024c46020a1d6ac68a5df989804142))
|
||||
|
||||
## [1.51.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-01-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.51.1",
|
||||
"version": "1.53.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -19,6 +19,7 @@
|
||||
"@standardnotes/api": "workspace:^",
|
||||
"@standardnotes/auth": "^3.19.4",
|
||||
"@standardnotes/common": "^1.45.0",
|
||||
"@standardnotes/domain-core": "^1.11.0",
|
||||
"@standardnotes/encryption": "workspace:^",
|
||||
"@standardnotes/files": "workspace:^",
|
||||
"@standardnotes/models": "workspace:^",
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||
import { SessionBody } from '@standardnotes/responses'
|
||||
|
||||
export interface AuthClientInterface {
|
||||
generateRecoveryCodes(): Promise<string | false>
|
||||
recoveryKeyParams(dto: {
|
||||
username: string
|
||||
codeChallenge: string
|
||||
recoveryCodes: string
|
||||
}): Promise<AnyKeyParamsContent | false>
|
||||
signInWithRecoveryCodes(dto: {
|
||||
username: string
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
}): Promise<
|
||||
| {
|
||||
keyParams: AnyKeyParamsContent
|
||||
session: SessionBody
|
||||
user: {
|
||||
uuid: string
|
||||
email: string
|
||||
protocolVersion: string
|
||||
}
|
||||
}
|
||||
| false
|
||||
>
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { AuthApiServiceInterface } from '@standardnotes/api'
|
||||
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||
import { SessionBody } from '@standardnotes/responses'
|
||||
|
||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||
import { AbstractService } from '../Service/AbstractService'
|
||||
import { AuthClientInterface } from './AuthClientInterface'
|
||||
|
||||
export class AuthManager extends AbstractService implements AuthClientInterface {
|
||||
constructor(
|
||||
private authApiService: AuthApiServiceInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
}
|
||||
|
||||
async generateRecoveryCodes(): Promise<string | false> {
|
||||
try {
|
||||
const result = await this.authApiService.generateRecoveryCodes()
|
||||
|
||||
if (result.data.error) {
|
||||
return false
|
||||
}
|
||||
|
||||
return result.data.recoveryCodes
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async recoveryKeyParams(dto: {
|
||||
username: string
|
||||
codeChallenge: string
|
||||
recoveryCodes: string
|
||||
}): Promise<AnyKeyParamsContent | false> {
|
||||
try {
|
||||
const result = await this.authApiService.recoveryKeyParams(dto)
|
||||
|
||||
if (result.data.error) {
|
||||
return false
|
||||
}
|
||||
|
||||
return result.data.keyParams as AnyKeyParamsContent
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async signInWithRecoveryCodes(dto: {
|
||||
username: string
|
||||
password: string
|
||||
codeVerifier: string
|
||||
recoveryCodes: string
|
||||
}): Promise<
|
||||
| {
|
||||
keyParams: AnyKeyParamsContent
|
||||
session: SessionBody
|
||||
user: {
|
||||
uuid: string
|
||||
email: string
|
||||
protocolVersion: string
|
||||
}
|
||||
}
|
||||
| false
|
||||
> {
|
||||
try {
|
||||
const result = await this.authApiService.signInWithRecoveryCodes(dto)
|
||||
|
||||
if (result.data.error) {
|
||||
return false
|
||||
}
|
||||
|
||||
return {
|
||||
keyParams: result.data.key_params as AnyKeyParamsContent,
|
||||
session: result.data.session,
|
||||
user: result.data.user,
|
||||
}
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user