feat: add sending user requests to process (#1908)
* feat: add sending user requests to process * fix(snjs): yarn lock * fix(snjs): imports * fix: specs
This commit is contained in:
BIN
.yarn/cache/@standardnotes-common-npm-1.43.0-ad3f3ce881-5930059441.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-common-npm-1.43.0-ad3f3ce881-5930059441.zip
vendored
Normal file
Binary file not shown.
@@ -36,7 +36,7 @@
|
|||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/encryption": "workspace:*",
|
"@standardnotes/encryption": "workspace:*",
|
||||||
"@standardnotes/models": "workspace:*",
|
"@standardnotes/models": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
|
|||||||
5
packages/api/src/Domain/Client/User/UserApiOperations.ts
Normal file
5
packages/api/src/Domain/Client/User/UserApiOperations.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum UserApiOperations {
|
||||||
|
Registering,
|
||||||
|
SubmittingRequest,
|
||||||
|
DeletingAccount,
|
||||||
|
}
|
||||||
@@ -1,20 +1,35 @@
|
|||||||
import { ProtocolVersion } from '@standardnotes/common'
|
import { ProtocolVersion, UserRequestType } from '@standardnotes/common'
|
||||||
import { RootKeyParamsInterface } from '@standardnotes/models'
|
import { RootKeyParamsInterface } from '@standardnotes/models'
|
||||||
|
import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse'
|
||||||
|
|
||||||
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse'
|
||||||
import { UserServerInterface } from '../../Server'
|
import { UserServerInterface } from '../../Server'
|
||||||
|
import { UserRequestServerInterface } from '../../Server/UserRequest/UserRequestServerInterface'
|
||||||
|
|
||||||
|
import { UserApiOperations } from './UserApiOperations'
|
||||||
import { UserApiService } from './UserApiService'
|
import { UserApiService } from './UserApiService'
|
||||||
|
|
||||||
describe('UserApiService', () => {
|
describe('UserApiService', () => {
|
||||||
let userServer: UserServerInterface
|
let userServer: UserServerInterface
|
||||||
|
let userRequestServer: UserRequestServerInterface
|
||||||
let keyParams: RootKeyParamsInterface
|
let keyParams: RootKeyParamsInterface
|
||||||
|
|
||||||
const createService = () => new UserApiService(userServer)
|
const createService = () => new UserApiService(userServer, userRequestServer)
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
userServer = {} as jest.Mocked<UserServerInterface>
|
userServer = {} as jest.Mocked<UserServerInterface>
|
||||||
userServer.register = jest.fn().mockReturnValue({
|
userServer.register = jest.fn().mockReturnValue({
|
||||||
data: { user: { email: 'test@test.te', uuid: '1-2-3' } },
|
data: { user: { email: 'test@test.te', uuid: '1-2-3' } },
|
||||||
} as jest.Mocked<UserRegistrationResponse>)
|
} as jest.Mocked<UserRegistrationResponse>)
|
||||||
|
userServer.deleteAccount = jest.fn().mockReturnValue({
|
||||||
|
data: { message: 'Success' },
|
||||||
|
} as jest.Mocked<UserDeletionResponse>)
|
||||||
|
|
||||||
|
userRequestServer = {} as jest.Mocked<UserRequestServerInterface>
|
||||||
|
userRequestServer.submitUserRequest = jest.fn().mockReturnValue({
|
||||||
|
data: { success: true },
|
||||||
|
} as jest.Mocked<UserRequestResponse>)
|
||||||
|
|
||||||
keyParams = {} as jest.Mocked<RootKeyParamsInterface>
|
keyParams = {} as jest.Mocked<RootKeyParamsInterface>
|
||||||
keyParams.getPortableValue = jest.fn().mockReturnValue({
|
keyParams.getPortableValue = jest.fn().mockReturnValue({
|
||||||
@@ -51,8 +66,8 @@ describe('UserApiService', () => {
|
|||||||
|
|
||||||
it('should not register a user if it is already registering', async () => {
|
it('should not register a user if it is already registering', async () => {
|
||||||
const service = createService()
|
const service = createService()
|
||||||
Object.defineProperty(service, 'registering', {
|
Object.defineProperty(service, 'operationsInProgress', {
|
||||||
get: () => true,
|
get: () => new Map([[UserApiOperations.Registering, true]]),
|
||||||
})
|
})
|
||||||
|
|
||||||
let error = null
|
let error = null
|
||||||
@@ -84,4 +99,99 @@ describe('UserApiService', () => {
|
|||||||
|
|
||||||
expect(error).not.toBeNull()
|
expect(error).not.toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should submit a user request', async () => {
|
||||||
|
const response = await createService().submitUserRequest({
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
requestType: UserRequestType.ExitDiscount,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
data: {
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(userRequestServer.submitUserRequest).toHaveBeenCalledWith({
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
requestType: UserRequestType.ExitDiscount,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not submit a user request if it is already submitting', async () => {
|
||||||
|
const service = createService()
|
||||||
|
Object.defineProperty(service, 'operationsInProgress', {
|
||||||
|
get: () => new Map([[UserApiOperations.SubmittingRequest, true]]),
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await service.submitUserRequest({ userUuid: '1-2-3', requestType: UserRequestType.ExitDiscount })
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not submit a user request if the server fails', async () => {
|
||||||
|
userRequestServer.submitUserRequest = jest.fn().mockImplementation(() => {
|
||||||
|
throw new Error('Oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await createService().submitUserRequest({
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
requestType: UserRequestType.ExitDiscount,
|
||||||
|
})
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should delete a user', async () => {
|
||||||
|
const response = await createService().deleteAccount('1-2-3')
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
data: {
|
||||||
|
message: 'Success',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(userServer.deleteAccount).toHaveBeenCalledWith({
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not delete a user if it is already deleting', async () => {
|
||||||
|
const service = createService()
|
||||||
|
Object.defineProperty(service, 'operationsInProgress', {
|
||||||
|
get: () => new Map([[UserApiOperations.DeletingAccount, true]]),
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await service.deleteAccount('1-2-3')
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not delete a user if the server fails', async () => {
|
||||||
|
userServer.deleteAccount = jest.fn().mockImplementation(() => {
|
||||||
|
throw new Error('Oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
try {
|
||||||
|
await createService().deleteAccount('1-2-3')
|
||||||
|
} catch (caughtError) {
|
||||||
|
error = caughtError
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeNull()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,17 +1,57 @@
|
|||||||
import { RootKeyParamsInterface } from '@standardnotes/models'
|
import { RootKeyParamsInterface } from '@standardnotes/models'
|
||||||
|
import { UserRequestType } from '@standardnotes/common'
|
||||||
|
|
||||||
import { ErrorMessage } from '../../Error/ErrorMessage'
|
import { ErrorMessage } from '../../Error/ErrorMessage'
|
||||||
import { ApiCallError } from '../../Error/ApiCallError'
|
import { ApiCallError } from '../../Error/ApiCallError'
|
||||||
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
import { UserServerInterface } from '../../Server/User/UserServerInterface'
|
import { UserServerInterface } from '../../Server/User/UserServerInterface'
|
||||||
import { ApiVersion } from '../../Api/ApiVersion'
|
import { ApiVersion } from '../../Api/ApiVersion'
|
||||||
import { ApiEndpointParam } from '../../Request/ApiEndpointParam'
|
import { ApiEndpointParam } from '../../Request/ApiEndpointParam'
|
||||||
|
import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse'
|
||||||
|
import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse'
|
||||||
|
import { UserRequestServerInterface } from '../../Server/UserRequest/UserRequestServerInterface'
|
||||||
|
|
||||||
|
import { UserApiOperations } from './UserApiOperations'
|
||||||
import { UserApiServiceInterface } from './UserApiServiceInterface'
|
import { UserApiServiceInterface } from './UserApiServiceInterface'
|
||||||
|
|
||||||
export class UserApiService implements UserApiServiceInterface {
|
export class UserApiService implements UserApiServiceInterface {
|
||||||
private registering: boolean
|
private operationsInProgress: Map<UserApiOperations, boolean>
|
||||||
|
|
||||||
constructor(private userServer: UserServerInterface) {
|
constructor(private userServer: UserServerInterface, private userRequestServer: UserRequestServerInterface) {
|
||||||
this.registering = false
|
this.operationsInProgress = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAccount(userUuid: string): Promise<UserDeletionResponse> {
|
||||||
|
this.lockOperation(UserApiOperations.DeletingAccount)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.userServer.deleteAccount({
|
||||||
|
userUuid: userUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.unlockOperation(UserApiOperations.DeletingAccount)
|
||||||
|
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
throw new ApiCallError(ErrorMessage.GenericRegistrationFail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitUserRequest(dto: { userUuid: string; requestType: UserRequestType }): Promise<UserRequestResponse> {
|
||||||
|
this.lockOperation(UserApiOperations.SubmittingRequest)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.userRequestServer.submitUserRequest({
|
||||||
|
userUuid: dto.userUuid,
|
||||||
|
requestType: dto.requestType,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.unlockOperation(UserApiOperations.SubmittingRequest)
|
||||||
|
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
throw new ApiCallError(ErrorMessage.GenericRegistrationFail)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(registerDTO: {
|
async register(registerDTO: {
|
||||||
@@ -20,10 +60,7 @@ export class UserApiService implements UserApiServiceInterface {
|
|||||||
keyParams: RootKeyParamsInterface
|
keyParams: RootKeyParamsInterface
|
||||||
ephemeral: boolean
|
ephemeral: boolean
|
||||||
}): Promise<UserRegistrationResponse> {
|
}): Promise<UserRegistrationResponse> {
|
||||||
if (this.registering) {
|
this.lockOperation(UserApiOperations.Registering)
|
||||||
throw new ApiCallError(ErrorMessage.RegistrationInProgress)
|
|
||||||
}
|
|
||||||
this.registering = true
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.userServer.register({
|
const response = await this.userServer.register({
|
||||||
@@ -34,11 +71,23 @@ export class UserApiService implements UserApiServiceInterface {
|
|||||||
...registerDTO.keyParams.getPortableValue(),
|
...registerDTO.keyParams.getPortableValue(),
|
||||||
})
|
})
|
||||||
|
|
||||||
this.registering = false
|
this.unlockOperation(UserApiOperations.Registering)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ApiCallError(ErrorMessage.GenericRegistrationFail)
|
throw new ApiCallError(ErrorMessage.GenericRegistrationFail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lockOperation(operation: UserApiOperations): void {
|
||||||
|
if (this.operationsInProgress.get(operation)) {
|
||||||
|
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.operationsInProgress.set(operation, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private unlockOperation(operation: UserApiOperations): void {
|
||||||
|
this.operationsInProgress.set(operation, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
import { UserRequestType, Uuid } from '@standardnotes/common'
|
||||||
import { RootKeyParamsInterface } from '@standardnotes/models'
|
import { RootKeyParamsInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
|
import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse'
|
||||||
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse'
|
||||||
|
|
||||||
export interface UserApiServiceInterface {
|
export interface UserApiServiceInterface {
|
||||||
register(registerDTO: {
|
register(registerDTO: {
|
||||||
@@ -8,4 +12,6 @@ export interface UserApiServiceInterface {
|
|||||||
keyParams: RootKeyParamsInterface
|
keyParams: RootKeyParamsInterface
|
||||||
ephemeral: boolean
|
ephemeral: boolean
|
||||||
}): Promise<UserRegistrationResponse>
|
}): Promise<UserRegistrationResponse>
|
||||||
|
submitUserRequest(dto: { userUuid: Uuid; requestType: UserRequestType }): Promise<UserRequestResponse>
|
||||||
|
deleteAccount(userUuid: string): Promise<UserDeletionResponse>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './Subscription/SubscriptionApiOperations'
|
export * from './Subscription/SubscriptionApiOperations'
|
||||||
export * from './Subscription/SubscriptionApiService'
|
export * from './Subscription/SubscriptionApiService'
|
||||||
export * from './Subscription/SubscriptionApiServiceInterface'
|
export * from './Subscription/SubscriptionApiServiceInterface'
|
||||||
|
export * from './User/UserApiOperations'
|
||||||
export * from './User/UserApiService'
|
export * from './User/UserApiService'
|
||||||
export * from './User/UserApiServiceInterface'
|
export * from './User/UserApiServiceInterface'
|
||||||
export * from './WebSocket/WebSocketApiService'
|
export * from './WebSocket/WebSocketApiService'
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { Uuid } from '@standardnotes/common'
|
||||||
|
|
||||||
|
export type UserDeletionRequestParams = {
|
||||||
|
userUuid: Uuid
|
||||||
|
[additionalParam: string]: unknown
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { UserRequestType, Uuid } from '@standardnotes/common'
|
||||||
|
|
||||||
|
export type UserRequestRequestParams = {
|
||||||
|
userUuid: Uuid
|
||||||
|
requestType: UserRequestType
|
||||||
|
[additionalParam: string]: unknown
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ export * from './Subscription/SubscriptionInviteDeclineRequestParams'
|
|||||||
export * from './Subscription/SubscriptionInviteListRequestParams'
|
export * from './Subscription/SubscriptionInviteListRequestParams'
|
||||||
export * from './Subscription/SubscriptionInviteRequestParams'
|
export * from './Subscription/SubscriptionInviteRequestParams'
|
||||||
export * from './User/UserRegistrationRequestParams'
|
export * from './User/UserRegistrationRequestParams'
|
||||||
|
export * from './UserRequest/UserRequestRequestParams'
|
||||||
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
|
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
|
||||||
export * from './Workspace/WorkspaceCreationRequestParams'
|
export * from './Workspace/WorkspaceCreationRequestParams'
|
||||||
export * from './Workspace/WorkspaceInvitationAcceptingRequestParams'
|
export * from './Workspace/WorkspaceInvitationAcceptingRequestParams'
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Either } from '@standardnotes/common'
|
||||||
|
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||||
|
import { HttpResponse } from '../../Http/HttpResponse'
|
||||||
|
|
||||||
|
import { UserDeletionResponseBody } from './UserDeletionResponseBody'
|
||||||
|
|
||||||
|
export interface UserDeletionResponse extends HttpResponse {
|
||||||
|
data: Either<UserDeletionResponseBody, HttpErrorResponseBody>
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export type UserDeletionResponseBody = {
|
||||||
|
message: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Either } from '@standardnotes/common'
|
||||||
|
|
||||||
|
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||||
|
import { HttpResponse } from '../../Http/HttpResponse'
|
||||||
|
import { UserRequestResponseBody } from './UserRequestResponseBody'
|
||||||
|
|
||||||
|
export interface UserRequestResponse extends HttpResponse {
|
||||||
|
data: Either<UserRequestResponseBody, HttpErrorResponseBody>
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export type UserRequestResponseBody = {
|
||||||
|
success: boolean
|
||||||
|
}
|
||||||
@@ -8,8 +8,12 @@ export * from './Subscription/SubscriptionInviteListResponse'
|
|||||||
export * from './Subscription/SubscriptionInviteListResponseBody'
|
export * from './Subscription/SubscriptionInviteListResponseBody'
|
||||||
export * from './Subscription/SubscriptionInviteResponse'
|
export * from './Subscription/SubscriptionInviteResponse'
|
||||||
export * from './Subscription/SubscriptionInviteResponseBody'
|
export * from './Subscription/SubscriptionInviteResponseBody'
|
||||||
|
export * from './User/UserDeletionResponse'
|
||||||
|
export * from './User/UserDeletionResponseBody'
|
||||||
export * from './User/UserRegistrationResponse'
|
export * from './User/UserRegistrationResponse'
|
||||||
export * from './User/UserRegistrationResponseBody'
|
export * from './User/UserRegistrationResponseBody'
|
||||||
|
export * from './UserRequest/UserRequestResponse'
|
||||||
|
export * from './UserRequest/UserRequestResponseBody'
|
||||||
export * from './WebSocket/WebSocketConnectionTokenResponse'
|
export * from './WebSocket/WebSocketConnectionTokenResponse'
|
||||||
export * from './WebSocket/WebSocketConnectionTokenResponseBody'
|
export * from './WebSocket/WebSocketConnectionTokenResponseBody'
|
||||||
export * from './Workspace/WorkspaceCreationResponse'
|
export * from './Workspace/WorkspaceCreationResponse'
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { Uuid } from '@standardnotes/common'
|
||||||
|
|
||||||
const UserPaths = {
|
const UserPaths = {
|
||||||
register: '/v1/users',
|
register: '/v1/users',
|
||||||
|
deleteAccount: (userUuid: Uuid) => `/v1/users/${userUuid}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Paths = {
|
export const Paths = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ProtocolVersion } from '@standardnotes/common'
|
import { ProtocolVersion } from '@standardnotes/common'
|
||||||
import { ApiVersion } from '../../Api'
|
import { ApiVersion } from '../../Api'
|
||||||
import { HttpServiceInterface } from '../../Http'
|
import { HttpServiceInterface } from '../../Http'
|
||||||
import { UserRegistrationResponse } from '../../Response'
|
import { UserDeletionResponse, UserRegistrationResponse } from '../../Response'
|
||||||
import { UserServer } from './UserServer'
|
import { UserServer } from './UserServer'
|
||||||
|
|
||||||
describe('UserServer', () => {
|
describe('UserServer', () => {
|
||||||
@@ -14,6 +14,9 @@ describe('UserServer', () => {
|
|||||||
httpService.post = jest.fn().mockReturnValue({
|
httpService.post = jest.fn().mockReturnValue({
|
||||||
data: { user: { email: 'test@test.te', uuid: '1-2-3' } },
|
data: { user: { email: 'test@test.te', uuid: '1-2-3' } },
|
||||||
} as jest.Mocked<UserRegistrationResponse>)
|
} as jest.Mocked<UserRegistrationResponse>)
|
||||||
|
httpService.delete = jest.fn().mockReturnValue({
|
||||||
|
data: { message: 'Success' },
|
||||||
|
} as jest.Mocked<UserDeletionResponse>)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should register a user', async () => {
|
it('should register a user', async () => {
|
||||||
@@ -36,4 +39,16 @@ describe('UserServer', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should delete a user', async () => {
|
||||||
|
const response = await createServer().deleteAccount({
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
data: {
|
||||||
|
message: 'Success',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
||||||
|
import { UserDeletionRequestParams } from '../../Request/User/UserDeletionRequestParams'
|
||||||
import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams'
|
import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams'
|
||||||
|
import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse'
|
||||||
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
import { Paths } from './Paths'
|
import { Paths } from './Paths'
|
||||||
import { UserServerInterface } from './UserServerInterface'
|
import { UserServerInterface } from './UserServerInterface'
|
||||||
@@ -7,6 +9,12 @@ import { UserServerInterface } from './UserServerInterface'
|
|||||||
export class UserServer implements UserServerInterface {
|
export class UserServer implements UserServerInterface {
|
||||||
constructor(private httpService: HttpServiceInterface) {}
|
constructor(private httpService: HttpServiceInterface) {}
|
||||||
|
|
||||||
|
async deleteAccount(params: UserDeletionRequestParams): Promise<UserDeletionResponse> {
|
||||||
|
const response = await this.httpService.delete(Paths.v1.deleteAccount(params.userUuid), params)
|
||||||
|
|
||||||
|
return response as UserDeletionResponse
|
||||||
|
}
|
||||||
|
|
||||||
async register(params: UserRegistrationRequestParams): Promise<UserRegistrationResponse> {
|
async register(params: UserRegistrationRequestParams): Promise<UserRegistrationResponse> {
|
||||||
const response = await this.httpService.post(Paths.v1.register, params)
|
const response = await this.httpService.post(Paths.v1.register, params)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import { UserDeletionRequestParams } from '../../Request/User/UserDeletionRequestParams'
|
||||||
import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams'
|
import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams'
|
||||||
|
import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse'
|
||||||
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
|
||||||
|
|
||||||
export interface UserServerInterface {
|
export interface UserServerInterface {
|
||||||
register(params: UserRegistrationRequestParams): Promise<UserRegistrationResponse>
|
register(params: UserRegistrationRequestParams): Promise<UserRegistrationResponse>
|
||||||
|
deleteAccount(params: UserDeletionRequestParams): Promise<UserDeletionResponse>
|
||||||
}
|
}
|
||||||
|
|||||||
11
packages/api/src/Domain/Server/UserRequest/Paths.ts
Normal file
11
packages/api/src/Domain/Server/UserRequest/Paths.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Uuid } from '@standardnotes/common'
|
||||||
|
|
||||||
|
const UserRequestPaths = {
|
||||||
|
submitUserRequest: (userUuid: Uuid) => `/v1/users/${userUuid}/requests`,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Paths = {
|
||||||
|
v1: {
|
||||||
|
...UserRequestPaths,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { UserRequestType } from '@standardnotes/common'
|
||||||
|
|
||||||
|
import { HttpServiceInterface } from '../../Http'
|
||||||
|
import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse'
|
||||||
|
|
||||||
|
import { UserRequestServer } from './UserRequestServer'
|
||||||
|
|
||||||
|
describe('UserRequestServer', () => {
|
||||||
|
let httpService: HttpServiceInterface
|
||||||
|
|
||||||
|
const createServer = () => new UserRequestServer(httpService)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
httpService = {} as jest.Mocked<HttpServiceInterface>
|
||||||
|
httpService.post = jest.fn().mockReturnValue({
|
||||||
|
data: { success: true },
|
||||||
|
} as jest.Mocked<UserRequestResponse>)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should submit a user request', async () => {
|
||||||
|
const response = await createServer().submitUserRequest({
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
requestType: UserRequestType.ExitDiscount,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response).toEqual({
|
||||||
|
data: {
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
||||||
|
import { UserRequestRequestParams } from '../../Request/UserRequest/UserRequestRequestParams'
|
||||||
|
import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse'
|
||||||
|
|
||||||
|
import { Paths } from './Paths'
|
||||||
|
import { UserRequestServerInterface } from './UserRequestServerInterface'
|
||||||
|
|
||||||
|
export class UserRequestServer implements UserRequestServerInterface {
|
||||||
|
constructor(private httpService: HttpServiceInterface) {}
|
||||||
|
|
||||||
|
async submitUserRequest(params: UserRequestRequestParams): Promise<UserRequestResponse> {
|
||||||
|
const response = await this.httpService.post(Paths.v1.submitUserRequest(params.userUuid), params)
|
||||||
|
|
||||||
|
return response as UserRequestResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { UserRequestRequestParams } from '../../Request/UserRequest/UserRequestRequestParams'
|
||||||
|
import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse'
|
||||||
|
|
||||||
|
export interface UserRequestServerInterface {
|
||||||
|
submitUserRequest(params: UserRequestRequestParams): Promise<UserRequestResponse>
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ export * from './Subscription/SubscriptionServer'
|
|||||||
export * from './Subscription/SubscriptionServerInterface'
|
export * from './Subscription/SubscriptionServerInterface'
|
||||||
export * from './User/UserServer'
|
export * from './User/UserServer'
|
||||||
export * from './User/UserServerInterface'
|
export * from './User/UserServerInterface'
|
||||||
|
export * from './UserRequest/UserRequestServer'
|
||||||
|
export * from './UserRequest/UserRequestServerInterface'
|
||||||
export * from './WebSocket/WebSocketServer'
|
export * from './WebSocket/WebSocketServer'
|
||||||
export * from './WebSocket/WebSocketServerInterface'
|
export * from './WebSocket/WebSocketServerInterface'
|
||||||
export * from './Workspace/WorkspaceServer'
|
export * from './Workspace/WorkspaceServer'
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/models": "workspace:*",
|
"@standardnotes/models": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
"@standardnotes/sncrypto-common": "workspace:*",
|
"@standardnotes/sncrypto-common": "workspace:*",
|
||||||
|
|||||||
@@ -1,54 +1,67 @@
|
|||||||
import { ProtocolVersion } from '@standardnotes/common'
|
import { KeyParamsOrigination, ProtocolVersion } from '@standardnotes/common'
|
||||||
import {
|
import {
|
||||||
BackupFile,
|
BackupFile,
|
||||||
DecryptedPayloadInterface,
|
DecryptedPayloadInterface,
|
||||||
EncryptedPayloadInterface,
|
EncryptedPayloadInterface,
|
||||||
ItemContent,
|
ItemContent,
|
||||||
|
ItemsKeyInterface,
|
||||||
RootKeyInterface,
|
RootKeyInterface,
|
||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||||
|
|
||||||
import { SNRootKeyParams } from '../../Keys/RootKey/RootKeyParams'
|
import { SNRootKeyParams } from '../../Keys/RootKey/RootKeyParams'
|
||||||
import { KeyedDecryptionSplit } from '../../Split/KeyedDecryptionSplit'
|
import { KeyedDecryptionSplit } from '../../Split/KeyedDecryptionSplit'
|
||||||
import { KeyedEncryptionSplit } from '../../Split/KeyedEncryptionSplit'
|
import { KeyedEncryptionSplit } from '../../Split/KeyedEncryptionSplit'
|
||||||
|
|
||||||
export interface EncryptionProviderInterface {
|
export interface EncryptionProviderInterface {
|
||||||
encryptSplitSingle(split: KeyedEncryptionSplit): Promise<EncryptedPayloadInterface>
|
encryptSplitSingle(split: KeyedEncryptionSplit): Promise<EncryptedPayloadInterface>
|
||||||
|
|
||||||
encryptSplit(split: KeyedEncryptionSplit): Promise<EncryptedPayloadInterface[]>
|
encryptSplit(split: KeyedEncryptionSplit): Promise<EncryptedPayloadInterface[]>
|
||||||
|
|
||||||
decryptSplitSingle<
|
decryptSplitSingle<
|
||||||
C extends ItemContent = ItemContent,
|
C extends ItemContent = ItemContent,
|
||||||
P extends DecryptedPayloadInterface<C> = DecryptedPayloadInterface<C>,
|
P extends DecryptedPayloadInterface<C> = DecryptedPayloadInterface<C>,
|
||||||
>(
|
>(
|
||||||
split: KeyedDecryptionSplit,
|
split: KeyedDecryptionSplit,
|
||||||
): Promise<P | EncryptedPayloadInterface>
|
): Promise<P | EncryptedPayloadInterface>
|
||||||
|
|
||||||
decryptSplit<
|
decryptSplit<
|
||||||
C extends ItemContent = ItemContent,
|
C extends ItemContent = ItemContent,
|
||||||
P extends DecryptedPayloadInterface<C> = DecryptedPayloadInterface<C>,
|
P extends DecryptedPayloadInterface<C> = DecryptedPayloadInterface<C>,
|
||||||
>(
|
>(
|
||||||
split: KeyedDecryptionSplit,
|
split: KeyedDecryptionSplit,
|
||||||
): Promise<(P | EncryptedPayloadInterface)[]>
|
): Promise<(P | EncryptedPayloadInterface)[]>
|
||||||
|
|
||||||
hasRootKeyEncryptionSource(): boolean
|
hasRootKeyEncryptionSource(): boolean
|
||||||
|
|
||||||
getKeyEmbeddedKeyParams(key: EncryptedPayloadInterface): SNRootKeyParams | undefined
|
getKeyEmbeddedKeyParams(key: EncryptedPayloadInterface): SNRootKeyParams | undefined
|
||||||
|
|
||||||
computeRootKey(password: string, keyParams: SNRootKeyParams): Promise<RootKeyInterface>
|
computeRootKey(password: string, keyParams: SNRootKeyParams): Promise<RootKeyInterface>
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns The versions that this library supports.
|
|
||||||
*/
|
|
||||||
supportedVersions(): ProtocolVersion[]
|
supportedVersions(): ProtocolVersion[]
|
||||||
|
|
||||||
getUserVersion(): ProtocolVersion | undefined
|
getUserVersion(): ProtocolVersion | undefined
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts a backup file using user-inputted password
|
|
||||||
* @param password - The raw user password associated with this backup file
|
|
||||||
*/
|
|
||||||
decryptBackupFile(
|
decryptBackupFile(
|
||||||
file: BackupFile,
|
file: BackupFile,
|
||||||
password?: string,
|
password?: string,
|
||||||
): Promise<ClientDisplayableError | (EncryptedPayloadInterface | DecryptedPayloadInterface)[]>
|
): Promise<ClientDisplayableError | (EncryptedPayloadInterface | DecryptedPayloadInterface)[]>
|
||||||
|
hasAccount(): boolean
|
||||||
|
decryptErroredPayloads(): Promise<void>
|
||||||
|
deleteWorkspaceSpecificKeyStateFromDevice(): Promise<void>
|
||||||
|
hasPasscode(): boolean
|
||||||
|
createRootKey(
|
||||||
|
identifier: string,
|
||||||
|
password: string,
|
||||||
|
origination: KeyParamsOrigination,
|
||||||
|
version?: ProtocolVersion,
|
||||||
|
): Promise<RootKeyInterface>
|
||||||
|
setNewRootKeyWrapper(wrappingKey: RootKeyInterface): Promise<void>
|
||||||
|
removePasscode(): Promise<void>
|
||||||
|
validateAccountPassword(password: string): Promise<
|
||||||
|
| {
|
||||||
|
valid: true
|
||||||
|
artifacts: {
|
||||||
|
rootKey: RootKeyInterface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
valid: boolean
|
||||||
|
}
|
||||||
|
>
|
||||||
|
createNewItemsKeyWithRollback(): Promise<() => Promise<void>>
|
||||||
|
reencryptItemsKeys(): Promise<void>
|
||||||
|
getSureDefaultItemsKey(): ItemsKeyInterface
|
||||||
|
getRootKeyParams(): Promise<SNRootKeyParams | undefined>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/auth": "^3.19.4",
|
"@standardnotes/auth": "^3.19.4",
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/security": "^1.2.0",
|
"@standardnotes/security": "^1.2.0",
|
||||||
"reflect-metadata": "^0.1.13"
|
"reflect-metadata": "^0.1.13"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/files": "workspace:*",
|
"@standardnotes/files": "workspace:*",
|
||||||
"@standardnotes/utils": "workspace:*",
|
"@standardnotes/utils": "workspace:*",
|
||||||
"@types/wicg-file-system-access": "^2020.9.5",
|
"@types/wicg-file-system-access": "^2020.9.5",
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"ts-jest": "^28.0.5"
|
"ts-jest": "^28.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/encryption": "workspace:*",
|
"@standardnotes/encryption": "workspace:*",
|
||||||
"@standardnotes/models": "workspace:*",
|
"@standardnotes/models": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/features": "workspace:*",
|
"@standardnotes/features": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
"@standardnotes/utils": "workspace:*",
|
"@standardnotes/utils": "workspace:*",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"ts-jest": "^28.0.5"
|
"ts-jest": "^28.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/features": "workspace:*",
|
"@standardnotes/features": "workspace:*",
|
||||||
"@standardnotes/security": "^1.1.0",
|
"@standardnotes/security": "^1.1.0",
|
||||||
"reflect-metadata": "^0.1.13"
|
"reflect-metadata": "^0.1.13"
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
branches: 9,
|
branches: 6,
|
||||||
functions: 10,
|
functions: 9,
|
||||||
lines: 16,
|
lines: 13,
|
||||||
statements: 16
|
statements: 13
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,12 +26,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/api": "workspace:^",
|
"@standardnotes/api": "workspace:^",
|
||||||
"@standardnotes/auth": "^3.19.4",
|
"@standardnotes/auth": "^3.19.4",
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/encryption": "workspace:^",
|
"@standardnotes/encryption": "workspace:^",
|
||||||
"@standardnotes/files": "workspace:^",
|
"@standardnotes/files": "workspace:^",
|
||||||
"@standardnotes/models": "workspace:^",
|
"@standardnotes/models": "workspace:^",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
"@standardnotes/security": "^1.2.0",
|
"@standardnotes/security": "^1.2.0",
|
||||||
|
"@standardnotes/sncrypto-common": "workspace:^",
|
||||||
"@standardnotes/utils": "workspace:*",
|
"@standardnotes/utils": "workspace:*",
|
||||||
"reflect-metadata": "^0.1.13"
|
"reflect-metadata": "^0.1.13"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { StorageValueModes } from '../Storage/StorageTypes'
|
|||||||
|
|
||||||
import { DeinitMode } from './DeinitMode'
|
import { DeinitMode } from './DeinitMode'
|
||||||
import { DeinitSource } from './DeinitSource'
|
import { DeinitSource } from './DeinitSource'
|
||||||
import { UserClientInterface } from './UserClientInterface'
|
import { UserClientInterface } from '../User/UserClientInterface'
|
||||||
|
|
||||||
export interface ApplicationInterface {
|
export interface ApplicationInterface {
|
||||||
deinit(mode: DeinitMode, source: DeinitSource): void
|
deinit(mode: DeinitMode, source: DeinitSource): void
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { ChallengeModalTitle, ChallengeStrings } from '../Api/Messages'
|
|
||||||
import { assertUnreachable } from '@standardnotes/utils'
|
import { assertUnreachable } from '@standardnotes/utils'
|
||||||
import { ChallengeValidation, ChallengeReason, ChallengeInterface, ChallengePrompt } from '@standardnotes/services'
|
import { ChallengeModalTitle, ChallengeStrings } from '../Strings/Messages'
|
||||||
|
import { ChallengeInterface } from './ChallengeInterface'
|
||||||
|
import { ChallengePrompt } from './Prompt/ChallengePrompt'
|
||||||
|
import { ChallengeReason } from './Types/ChallengeReason'
|
||||||
|
import { ChallengeValidation } from './Types/ChallengeValidation'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A challenge is a stateless description of what the client needs to provide
|
* A challenge is a stateless description of what the client needs to provide
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { RootKeyInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
import { AbstractService } from '../Service/AbstractService'
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
import { ChallengeInterface } from './ChallengeInterface'
|
import { ChallengeInterface } from './ChallengeInterface'
|
||||||
import { ChallengePromptInterface } from './Prompt/ChallengePromptInterface'
|
import { ChallengePromptInterface } from './Prompt/ChallengePromptInterface'
|
||||||
@@ -10,7 +12,6 @@ export interface ChallengeServiceInterface extends AbstractService {
|
|||||||
* For non-validated challenges, will resolve when the first value is submitted.
|
* For non-validated challenges, will resolve when the first value is submitted.
|
||||||
*/
|
*/
|
||||||
promptForChallengeResponse(challenge: ChallengeInterface): Promise<ChallengeResponseInterface | undefined>
|
promptForChallengeResponse(challenge: ChallengeInterface): Promise<ChallengeResponseInterface | undefined>
|
||||||
|
|
||||||
createChallenge(
|
createChallenge(
|
||||||
prompts: ChallengePromptInterface[],
|
prompts: ChallengePromptInterface[],
|
||||||
reason: ChallengeReason,
|
reason: ChallengeReason,
|
||||||
@@ -18,6 +19,19 @@ export interface ChallengeServiceInterface extends AbstractService {
|
|||||||
heading?: string,
|
heading?: string,
|
||||||
subheading?: string,
|
subheading?: string,
|
||||||
): ChallengeInterface
|
): ChallengeInterface
|
||||||
|
|
||||||
completeChallenge(challenge: ChallengeInterface): void
|
completeChallenge(challenge: ChallengeInterface): void
|
||||||
|
getWrappingKeyIfApplicable(passcode?: string): Promise<
|
||||||
|
| {
|
||||||
|
canceled?: undefined
|
||||||
|
wrappingKey?: undefined
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
canceled: boolean
|
||||||
|
wrappingKey?: undefined
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
wrappingKey: RootKeyInterface
|
||||||
|
canceled?: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from './Challenge'
|
||||||
export * from './ChallengeInterface'
|
export * from './ChallengeInterface'
|
||||||
export * from './ChallengeResponseInterface'
|
export * from './ChallengeResponseInterface'
|
||||||
export * from './ChallengeServiceInterface'
|
export * from './ChallengeServiceInterface'
|
||||||
|
|||||||
@@ -44,50 +44,22 @@ export interface ItemManagerInterface extends AbstractService {
|
|||||||
contentType: ContentType | ContentType[],
|
contentType: ContentType | ContentType[],
|
||||||
callback: ItemManagerChangeObserverCallback<I>,
|
callback: ItemManagerChangeObserverCallback<I>,
|
||||||
): () => void
|
): () => void
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks the item as deleted and needing sync.
|
|
||||||
*/
|
|
||||||
setItemToBeDeleted(itemToLookupUuidFor: DecryptedItemInterface, source?: PayloadEmitSource): Promise<void>
|
setItemToBeDeleted(itemToLookupUuidFor: DecryptedItemInterface, source?: PayloadEmitSource): Promise<void>
|
||||||
|
|
||||||
setItemsToBeDeleted(itemsToLookupUuidsFor: DecryptedItemInterface[]): Promise<void>
|
setItemsToBeDeleted(itemsToLookupUuidsFor: DecryptedItemInterface[]): Promise<void>
|
||||||
|
|
||||||
setItemsDirty(
|
setItemsDirty(
|
||||||
itemsToLookupUuidsFor: DecryptedItemInterface[],
|
itemsToLookupUuidsFor: DecryptedItemInterface[],
|
||||||
isUserModified?: boolean,
|
isUserModified?: boolean,
|
||||||
): Promise<DecryptedItemInterface[]>
|
): Promise<DecryptedItemInterface[]>
|
||||||
|
|
||||||
get items(): DecryptedItemInterface[]
|
get items(): DecryptedItemInterface[]
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the item as-is by reading its payload value. This function will not
|
|
||||||
* modify item in any way (such as marking it as dirty). It is up to the caller
|
|
||||||
* to pass in a dirtied item if that is their intention.
|
|
||||||
*/
|
|
||||||
insertItem(item: DecryptedItemInterface): Promise<DecryptedItemInterface>
|
insertItem(item: DecryptedItemInterface): Promise<DecryptedItemInterface>
|
||||||
|
|
||||||
emitItemFromPayload(payload: DecryptedPayloadInterface, source: PayloadEmitSource): Promise<DecryptedItemInterface>
|
emitItemFromPayload(payload: DecryptedPayloadInterface, source: PayloadEmitSource): Promise<DecryptedItemInterface>
|
||||||
|
|
||||||
getItems<T extends DecryptedItemInterface>(contentType: ContentType | ContentType[]): T[]
|
getItems<T extends DecryptedItemInterface>(contentType: ContentType | ContentType[]): T[]
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all non-deleted items keys
|
|
||||||
*/
|
|
||||||
getDisplayableItemsKeys(): ItemsKeyInterface[]
|
getDisplayableItemsKeys(): ItemsKeyInterface[]
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an item and conditionally maps it and marks it as dirty.
|
|
||||||
* @param needsSync - Whether to mark the item as needing sync
|
|
||||||
*/
|
|
||||||
createItem<T extends DecryptedItemInterface, C extends ItemContent = ItemContent>(
|
createItem<T extends DecryptedItemInterface, C extends ItemContent = ItemContent>(
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
content: C,
|
content: C,
|
||||||
needsSync?: boolean,
|
needsSync?: boolean,
|
||||||
): Promise<T>
|
): Promise<T>
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an unmanaged item that can later be inserted via `insertItem`
|
|
||||||
*/
|
|
||||||
createTemplateItem<
|
createTemplateItem<
|
||||||
C extends ItemContent = ItemContent,
|
C extends ItemContent = ItemContent,
|
||||||
I extends DecryptedItemInterface<C> = DecryptedItemInterface<C>,
|
I extends DecryptedItemInterface<C> = DecryptedItemInterface<C>,
|
||||||
@@ -96,12 +68,6 @@ export interface ItemManagerInterface extends AbstractService {
|
|||||||
content?: C,
|
content?: C,
|
||||||
override?: Partial<DecryptedPayload<C>>,
|
override?: Partial<DecryptedPayload<C>>,
|
||||||
): I
|
): I
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumers wanting to modify an item should run it through this block,
|
|
||||||
* so that data is properly mapped through our function, and latest state
|
|
||||||
* is properly reconciled.
|
|
||||||
*/
|
|
||||||
changeItem<
|
changeItem<
|
||||||
M extends DecryptedItemMutator = DecryptedItemMutator,
|
M extends DecryptedItemMutator = DecryptedItemMutator,
|
||||||
I extends DecryptedItemInterface = DecryptedItemInterface,
|
I extends DecryptedItemInterface = DecryptedItemInterface,
|
||||||
@@ -112,7 +78,6 @@ export interface ItemManagerInterface extends AbstractService {
|
|||||||
emitSource?: PayloadEmitSource,
|
emitSource?: PayloadEmitSource,
|
||||||
payloadSourceKey?: string,
|
payloadSourceKey?: string,
|
||||||
): Promise<I>
|
): Promise<I>
|
||||||
|
|
||||||
changeItemsKey(
|
changeItemsKey(
|
||||||
itemToLookupUuidFor: ItemsKeyInterface,
|
itemToLookupUuidFor: ItemsKeyInterface,
|
||||||
mutate: (mutator: ItemsKeyMutatorInterface) => void,
|
mutate: (mutator: ItemsKeyMutatorInterface) => void,
|
||||||
@@ -120,16 +85,15 @@ export interface ItemManagerInterface extends AbstractService {
|
|||||||
emitSource?: PayloadEmitSource,
|
emitSource?: PayloadEmitSource,
|
||||||
payloadSourceKey?: string,
|
payloadSourceKey?: string,
|
||||||
): Promise<ItemsKeyInterface>
|
): Promise<ItemsKeyInterface>
|
||||||
|
|
||||||
itemsMatchingPredicate<T extends DecryptedItemInterface>(
|
itemsMatchingPredicate<T extends DecryptedItemInterface>(
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
predicate: PredicateInterface<T>,
|
predicate: PredicateInterface<T>,
|
||||||
): T[]
|
): T[]
|
||||||
|
|
||||||
itemsMatchingPredicates<T extends DecryptedItemInterface>(
|
itemsMatchingPredicates<T extends DecryptedItemInterface>(
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
predicates: PredicateInterface<T>[],
|
predicates: PredicateInterface<T>[],
|
||||||
): T[]
|
): T[]
|
||||||
|
|
||||||
subItemsMatchingPredicates<T extends DecryptedItemInterface>(items: T[], predicates: PredicateInterface<T>[]): T[]
|
subItemsMatchingPredicates<T extends DecryptedItemInterface>(items: T[], predicates: PredicateInterface<T>[]): T[]
|
||||||
|
removeAllItemsFromMemory(): Promise<void>
|
||||||
|
getDirtyItems(): (DecryptedItemInterface | DeletedItemInterface)[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export enum MobileUnlockTiming {
|
||||||
|
Immediately = 'immediately',
|
||||||
|
OnQuit = 'on-quit',
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ChallengeReason } from '@standardnotes/services'
|
|
||||||
import { DecryptedItem } from '@standardnotes/models'
|
import { DecryptedItem } from '@standardnotes/models'
|
||||||
import { TimingDisplayOption, MobileUnlockTiming } from './MobileUnlockTiming'
|
import { ChallengeReason } from '../Challenge'
|
||||||
|
import { MobileUnlockTiming } from './MobileUnlockTiming'
|
||||||
|
import { TimingDisplayOption } from './TimingDisplayOption'
|
||||||
|
|
||||||
export interface ProtectionsClientInterface {
|
export interface ProtectionsClientInterface {
|
||||||
authorizeProtectedActionForItems<T extends DecryptedItem>(files: T[], challengeReason: ChallengeReason): Promise<T[]>
|
authorizeProtectedActionForItems<T extends DecryptedItem>(files: T[], challengeReason: ChallengeReason): Promise<T[]>
|
||||||
@@ -16,4 +17,11 @@ export interface ProtectionsClientInterface {
|
|||||||
hasBiometricsEnabled(): boolean
|
hasBiometricsEnabled(): boolean
|
||||||
enableBiometrics(): boolean
|
enableBiometrics(): boolean
|
||||||
disableBiometrics(): Promise<boolean>
|
disableBiometrics(): Promise<boolean>
|
||||||
|
authorizeAction(
|
||||||
|
reason: ChallengeReason,
|
||||||
|
dto: { fallBackToAccountPassword: boolean; requireAccountPassword: boolean; forcePrompt: boolean },
|
||||||
|
): Promise<boolean>
|
||||||
|
authorizeAddingPasscode(): Promise<boolean>
|
||||||
|
authorizeRemovingPasscode(): Promise<boolean>
|
||||||
|
authorizeChangingPasscode(): Promise<boolean>
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
export enum MobileUnlockTiming {
|
import { MobileUnlockTiming } from './MobileUnlockTiming'
|
||||||
Immediately = 'immediately',
|
|
||||||
OnQuit = 'on-quit',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TimingDisplayOption = {
|
export type TimingDisplayOption = {
|
||||||
title: string
|
title: string
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||||
|
import { RootKeyInterface } from '@standardnotes/models'
|
||||||
|
import { HttpResponse } from '@standardnotes/responses'
|
||||||
|
|
||||||
|
export type SessionManagerResponse = {
|
||||||
|
response: HttpResponse
|
||||||
|
rootKey?: RootKeyInterface
|
||||||
|
keyParams?: AnyKeyParamsContent
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { UserRegistrationResponseBody } from '@standardnotes/api'
|
||||||
|
import { ProtocolVersion } from '@standardnotes/common'
|
||||||
|
import { RootKeyInterface } from '@standardnotes/models'
|
||||||
|
import { ClientDisplayableError, HttpResponse, SignInResponse, User } from '@standardnotes/responses'
|
||||||
|
import { Base64String } from '@standardnotes/sncrypto-common'
|
||||||
|
|
||||||
|
import { SessionManagerResponse } from './SessionManagerResponse'
|
||||||
|
|
||||||
|
export interface SessionsClientInterface {
|
||||||
|
createDemoShareToken(): Promise<Base64String | ClientDisplayableError>
|
||||||
|
populateSessionFromDemoShareToken(token: Base64String): Promise<void>
|
||||||
|
getUser(): User | undefined
|
||||||
|
register(email: string, password: string, ephemeral: boolean): Promise<UserRegistrationResponseBody>
|
||||||
|
signIn(
|
||||||
|
email: string,
|
||||||
|
password: string,
|
||||||
|
strict: boolean,
|
||||||
|
ephemeral: boolean,
|
||||||
|
minAllowedVersion?: ProtocolVersion,
|
||||||
|
): Promise<SessionManagerResponse>
|
||||||
|
getSureUser(): User
|
||||||
|
bypassChecksAndSignInWithRootKey(
|
||||||
|
email: string,
|
||||||
|
rootKey: RootKeyInterface,
|
||||||
|
ephemeral: boolean,
|
||||||
|
): Promise<SignInResponse | HttpResponse>
|
||||||
|
signOut(): Promise<void>
|
||||||
|
changeCredentials(parameters: {
|
||||||
|
currentServerPassword: string
|
||||||
|
newRootKey: RootKeyInterface
|
||||||
|
wrappingKey?: RootKeyInterface
|
||||||
|
newEmail?: string
|
||||||
|
}): Promise<SessionManagerResponse>
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import { PayloadInterface, RootKeyInterface } from '@standardnotes/models'
|
import { FullyFormedPayloadInterface, PayloadInterface, RootKeyInterface } from '@standardnotes/models'
|
||||||
import { StorageValueModes } from './StorageTypes'
|
import { StoragePersistencePolicies, StorageValueModes } from './StorageTypes'
|
||||||
|
|
||||||
export interface StorageServiceInterface {
|
export interface StorageServiceInterface {
|
||||||
getValue<T>(key: string, mode?: StorageValueModes, defaultValue?: T): T
|
getValue<T>(key: string, mode?: StorageValueModes, defaultValue?: T): T
|
||||||
|
|
||||||
canDecryptWithKey(key: RootKeyInterface): Promise<boolean>
|
canDecryptWithKey(key: RootKeyInterface): Promise<boolean>
|
||||||
|
|
||||||
savePayload(payload: PayloadInterface): Promise<void>
|
savePayload(payload: PayloadInterface): Promise<void>
|
||||||
|
|
||||||
savePayloads(decryptedPayloads: PayloadInterface[]): Promise<void>
|
savePayloads(decryptedPayloads: PayloadInterface[]): Promise<void>
|
||||||
|
|
||||||
setValue(key: string, value: unknown, mode?: StorageValueModes): void
|
setValue(key: string, value: unknown, mode?: StorageValueModes): void
|
||||||
|
|
||||||
removeValue(key: string, mode?: StorageValueModes): Promise<void>
|
removeValue(key: string, mode?: StorageValueModes): Promise<void>
|
||||||
|
setPersistencePolicy(persistencePolicy: StoragePersistencePolicies): Promise<void>
|
||||||
|
clearAllData(): Promise<void>
|
||||||
|
forceDeletePayloads(payloads: FullyFormedPayloadInterface[]): Promise<void>
|
||||||
|
clearAllPayloads(): Promise<void>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
|
|
||||||
|
import { FullyFormedPayloadInterface } from '@standardnotes/models'
|
||||||
import { SyncOptions } from './SyncOptions'
|
import { SyncOptions } from './SyncOptions'
|
||||||
|
|
||||||
export interface SyncServiceInterface {
|
export interface SyncServiceInterface {
|
||||||
sync(options?: Partial<SyncOptions>): Promise<unknown>
|
sync(options?: Partial<SyncOptions>): Promise<unknown>
|
||||||
|
resetSyncState(): void
|
||||||
|
markAllItemsAsNeedingSyncAndPersist(): Promise<void>
|
||||||
|
downloadFirstSync(waitTimeOnFailureMs: number, otherSyncOptions?: Partial<SyncOptions>): Promise<void>
|
||||||
|
persistPayloads(payloads: FullyFormedPayloadInterface[]): Promise<void>
|
||||||
|
lockSyncing(): void
|
||||||
|
unlockSyncing(): void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { DeinitSource } from './DeinitSource'
|
import { DeinitSource } from '../Application/DeinitSource'
|
||||||
|
|
||||||
export interface UserClientInterface {
|
export interface UserClientInterface {
|
||||||
deleteAccount(): Promise<{
|
deleteAccount(): Promise<{
|
||||||
error: boolean
|
error: boolean
|
||||||
message?: string
|
message?: string
|
||||||
}>
|
}>
|
||||||
|
|
||||||
signOut(force?: boolean, source?: DeinitSource): Promise<void>
|
signOut(force?: boolean, source?: DeinitSource): Promise<void>
|
||||||
}
|
}
|
||||||
@@ -1,32 +1,29 @@
|
|||||||
import { Challenge } from '../Challenge'
|
import { EncryptionProviderInterface, SNRootKey, SNRootKeyParams } from '@standardnotes/encryption'
|
||||||
import { ChallengeService } from '../Challenge/ChallengeService'
|
|
||||||
import { SNRootKey, SNRootKeyParams } from '@standardnotes/encryption'
|
|
||||||
import { HttpResponse, SignInResponse, User } from '@standardnotes/responses'
|
import { HttpResponse, SignInResponse, User } from '@standardnotes/responses'
|
||||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
|
||||||
import { KeyParamsOrigination } from '@standardnotes/common'
|
import { KeyParamsOrigination } from '@standardnotes/common'
|
||||||
|
import { UuidGenerator } from '@standardnotes/utils'
|
||||||
|
import { UserApiServiceInterface, UserRegistrationResponseBody } from '@standardnotes/api'
|
||||||
|
|
||||||
|
import * as Messages from '../Strings/Messages'
|
||||||
|
import { InfoStrings } from '../Strings/InfoStrings'
|
||||||
|
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
|
||||||
|
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
|
||||||
|
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
|
||||||
|
import { AlertService } from '../Alert/AlertService'
|
||||||
import {
|
import {
|
||||||
AbstractService,
|
Challenge,
|
||||||
AlertService,
|
|
||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
|
ChallengeServiceInterface,
|
||||||
ChallengeValidation,
|
ChallengeValidation,
|
||||||
DeinitSource,
|
} from '../Challenge'
|
||||||
InternalEventBusInterface,
|
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||||
UserClientInterface,
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
StoragePersistencePolicies,
|
import { UserClientInterface } from './UserClientInterface'
|
||||||
EncryptionService,
|
import { DeinitSource } from '../Application/DeinitSource'
|
||||||
} from '@standardnotes/services'
|
import { StoragePersistencePolicies } from '../Storage/StorageTypes'
|
||||||
import { SNApiService } from './../Api/ApiService'
|
import { SessionsClientInterface } from '../Session/SessionsClientInterface'
|
||||||
import { SNProtectionService } from '../Protection/ProtectionService'
|
import { ProtectionsClientInterface } from '../Protection/ProtectionClientInterface'
|
||||||
import { SNSessionManager, MINIMUM_PASSWORD_LENGTH } from '../Session/SessionManager'
|
|
||||||
import { DiskStorageService } from '@Lib/Services/Storage/DiskStorageService'
|
|
||||||
import { SNSyncService } from '../Sync/SyncService'
|
|
||||||
import { Strings } from '../../Strings/index'
|
|
||||||
import { UuidGenerator } from '@standardnotes/utils'
|
|
||||||
import * as Messages from '../Api/Messages'
|
|
||||||
import { UserRegistrationResponseBody } from '@standardnotes/api'
|
|
||||||
|
|
||||||
const MINIMUM_PASSCODE_LENGTH = 1
|
|
||||||
|
|
||||||
export type CredentialsChangeFunctionResponse = { error?: { message: string } }
|
export type CredentialsChangeFunctionResponse = { error?: { message: string } }
|
||||||
export type AccountServiceResponse = HttpResponse
|
export type AccountServiceResponse = HttpResponse
|
||||||
@@ -44,16 +41,19 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
private signingIn = false
|
private signingIn = false
|
||||||
private registering = false
|
private registering = false
|
||||||
|
|
||||||
|
private readonly MINIMUM_PASSCODE_LENGTH = 1
|
||||||
|
private readonly MINIMUM_PASSWORD_LENGTH = 8
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private sessionManager: SNSessionManager,
|
private sessionManager: SessionsClientInterface,
|
||||||
private syncService: SNSyncService,
|
private syncService: SyncServiceInterface,
|
||||||
private storageService: DiskStorageService,
|
private storageService: StorageServiceInterface,
|
||||||
private itemManager: ItemManager,
|
private itemManager: ItemManagerInterface,
|
||||||
private protocolService: EncryptionService,
|
private protocolService: EncryptionProviderInterface,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private challengeService: ChallengeService,
|
private challengeService: ChallengeServiceInterface,
|
||||||
private protectionService: SNProtectionService,
|
private protectionService: ProtectionsClientInterface,
|
||||||
private apiService: SNApiService,
|
private userApiService: UserApiServiceInterface,
|
||||||
protected override internalEventBus: InternalEventBusInterface,
|
protected override internalEventBus: InternalEventBusInterface,
|
||||||
) {
|
) {
|
||||||
super(internalEventBus)
|
super(internalEventBus)
|
||||||
@@ -69,7 +69,7 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
;(this.alertService as unknown) = undefined
|
;(this.alertService as unknown) = undefined
|
||||||
;(this.challengeService as unknown) = undefined
|
;(this.challengeService as unknown) = undefined
|
||||||
;(this.protectionService as unknown) = undefined
|
;(this.protectionService as unknown) = undefined
|
||||||
;(this.apiService as unknown) = undefined
|
;(this.userApiService as unknown) = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,7 +204,9 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
}> {
|
}> {
|
||||||
if (
|
if (
|
||||||
!(await this.protectionService.authorizeAction(ChallengeReason.DeleteAccount, {
|
!(await this.protectionService.authorizeAction(ChallengeReason.DeleteAccount, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
requireAccountPassword: true,
|
requireAccountPassword: true,
|
||||||
|
forcePrompt: false,
|
||||||
}))
|
}))
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
@@ -214,17 +216,17 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uuid = this.sessionManager.getSureUser().uuid
|
const uuid = this.sessionManager.getSureUser().uuid
|
||||||
const response = await this.apiService.deleteAccount(uuid)
|
const response = await this.userApiService.deleteAccount(uuid)
|
||||||
if (response.error) {
|
if (response.data.error) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
message: response.error.message,
|
message: response.data.error.message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.signOut(true)
|
await this.signOut(true)
|
||||||
|
|
||||||
void this.alertService.alert(Strings.Info.AccountDeleted)
|
void this.alertService.alert(InfoStrings.AccountDeleted)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
error: false,
|
error: false,
|
||||||
@@ -239,7 +241,11 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
public async correctiveSignIn(rootKey: SNRootKey): Promise<HttpResponse | SignInResponse> {
|
public async correctiveSignIn(rootKey: SNRootKey): Promise<HttpResponse | SignInResponse> {
|
||||||
this.lockSyncing()
|
this.lockSyncing()
|
||||||
|
|
||||||
const response = await this.sessionManager.bypassChecksAndSignInWithRootKey(rootKey.keyParams.identifier, rootKey)
|
const response = await this.sessionManager.bypassChecksAndSignInWithRootKey(
|
||||||
|
rootKey.keyParams.identifier,
|
||||||
|
rootKey,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
if (!response.error) {
|
if (!response.error) {
|
||||||
await this.notifyEvent(AccountEvent.SignedInOrRegistered)
|
await this.notifyEvent(AccountEvent.SignedInOrRegistered)
|
||||||
@@ -381,7 +387,7 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async addPasscode(passcode: string): Promise<boolean> {
|
public async addPasscode(passcode: string): Promise<boolean> {
|
||||||
if (passcode.length < MINIMUM_PASSCODE_LENGTH) {
|
if (passcode.length < this.MINIMUM_PASSCODE_LENGTH) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!(await this.protectionService.authorizeAddingPasscode())) {
|
if (!(await this.protectionService.authorizeAddingPasscode())) {
|
||||||
@@ -424,7 +430,7 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
newPasscode: string,
|
newPasscode: string,
|
||||||
origination = KeyParamsOrigination.PasscodeChange,
|
origination = KeyParamsOrigination.PasscodeChange,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (newPasscode.length < MINIMUM_PASSCODE_LENGTH) {
|
if (newPasscode.length < this.MINIMUM_PASSCODE_LENGTH) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!(await this.protectionService.authorizeChangingPasscode())) {
|
if (!(await this.protectionService.authorizeChangingPasscode())) {
|
||||||
@@ -501,9 +507,9 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parameters.newPassword !== undefined && parameters.validateNewPasswordStrength) {
|
if (parameters.newPassword !== undefined && parameters.validateNewPasswordStrength) {
|
||||||
if (parameters.newPassword.length < MINIMUM_PASSWORD_LENGTH) {
|
if (parameters.newPassword.length < this.MINIMUM_PASSWORD_LENGTH) {
|
||||||
return {
|
return {
|
||||||
error: Error(Messages.InsufficientPasswordMessage(MINIMUM_PASSWORD_LENGTH)),
|
error: Error(Messages.InsufficientPasswordMessage(this.MINIMUM_PASSWORD_LENGTH)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ export * from './Application/ApplicationStage'
|
|||||||
export * from './Application/DeinitCallback'
|
export * from './Application/DeinitCallback'
|
||||||
export * from './Application/DeinitSource'
|
export * from './Application/DeinitSource'
|
||||||
export * from './Application/DeinitMode'
|
export * from './Application/DeinitMode'
|
||||||
export * from './Application/UserClientInterface'
|
export * from './User/UserClientInterface'
|
||||||
export * from './Application/WebApplicationInterface'
|
export * from './Application/WebApplicationInterface'
|
||||||
export * from './Backups/BackupService'
|
export * from './Backups/BackupService'
|
||||||
export * from './Challenge'
|
export * from './Challenge'
|
||||||
@@ -58,8 +58,13 @@ export * from './Item/ItemRelationshipDirection'
|
|||||||
export * from './Mutator/MutatorClientInterface'
|
export * from './Mutator/MutatorClientInterface'
|
||||||
export * from './Payloads/PayloadManagerInterface'
|
export * from './Payloads/PayloadManagerInterface'
|
||||||
export * from './Preferences/PreferenceServiceInterface'
|
export * from './Preferences/PreferenceServiceInterface'
|
||||||
|
export * from './Protection/MobileUnlockTiming'
|
||||||
|
export * from './Protection/ProtectionClientInterface'
|
||||||
|
export * from './Protection/TimingDisplayOption'
|
||||||
export * from './Service/AbstractService'
|
export * from './Service/AbstractService'
|
||||||
export * from './Service/ServiceInterface'
|
export * from './Service/ServiceInterface'
|
||||||
|
export * from './Session/SessionManagerResponse'
|
||||||
|
export * from './Session/SessionsClientInterface'
|
||||||
export * from './Status/StatusService'
|
export * from './Status/StatusService'
|
||||||
export * from './Status/StatusServiceInterface'
|
export * from './Status/StatusServiceInterface'
|
||||||
export * from './Storage/StorageKeys'
|
export * from './Storage/StorageKeys'
|
||||||
@@ -67,6 +72,8 @@ export * from './Storage/InMemoryStore'
|
|||||||
export * from './Storage/KeyValueStoreInterface'
|
export * from './Storage/KeyValueStoreInterface'
|
||||||
export * from './Storage/StorageServiceInterface'
|
export * from './Storage/StorageServiceInterface'
|
||||||
export * from './Storage/StorageTypes'
|
export * from './Storage/StorageTypes'
|
||||||
|
export * from './Strings/InfoStrings'
|
||||||
|
export * from './Strings/Messages'
|
||||||
export * from './Subscription/SubscriptionClientInterface'
|
export * from './Subscription/SubscriptionClientInterface'
|
||||||
export * from './Subscription/SubscriptionManager'
|
export * from './Subscription/SubscriptionManager'
|
||||||
export * from './Sync/SyncMode'
|
export * from './Sync/SyncMode'
|
||||||
@@ -74,5 +81,7 @@ export * from './Sync/SyncOptions'
|
|||||||
export * from './Sync/SyncQueueStrategy'
|
export * from './Sync/SyncQueueStrategy'
|
||||||
export * from './Sync/SyncServiceInterface'
|
export * from './Sync/SyncServiceInterface'
|
||||||
export * from './Sync/SyncSource'
|
export * from './Sync/SyncSource'
|
||||||
|
export * from './User/UserClientInterface'
|
||||||
|
export * from './User/UserService'
|
||||||
export * from './Workspace/WorkspaceClientInterface'
|
export * from './Workspace/WorkspaceClientInterface'
|
||||||
export * from './Workspace/WorkspaceManager'
|
export * from './Workspace/WorkspaceManager'
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
UserApiService,
|
UserApiService,
|
||||||
UserApiServiceInterface,
|
UserApiServiceInterface,
|
||||||
UserRegistrationResponseBody,
|
UserRegistrationResponseBody,
|
||||||
|
UserRequestServer,
|
||||||
|
UserRequestServerInterface,
|
||||||
UserServer,
|
UserServer,
|
||||||
UserServerInterface,
|
UserServerInterface,
|
||||||
WebSocketApiService,
|
WebSocketApiService,
|
||||||
@@ -52,6 +54,15 @@ import {
|
|||||||
WorkspaceClientInterface,
|
WorkspaceClientInterface,
|
||||||
WorkspaceManager,
|
WorkspaceManager,
|
||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
|
Challenge,
|
||||||
|
ErrorAlertStrings,
|
||||||
|
SessionsClientInterface,
|
||||||
|
ProtectionsClientInterface,
|
||||||
|
UserService,
|
||||||
|
ProtocolUpgradeStrings,
|
||||||
|
CredentialsChangeFunctionResponse,
|
||||||
|
SessionStrings,
|
||||||
|
AccountEvent,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { FilesClientInterface } from '@standardnotes/files'
|
import { FilesClientInterface } from '@standardnotes/files'
|
||||||
import { ComputePrivateUsername } from '@standardnotes/encryption'
|
import { ComputePrivateUsername } from '@standardnotes/encryption'
|
||||||
@@ -68,7 +79,7 @@ import { ClientDisplayableError } from '@standardnotes/responses'
|
|||||||
|
|
||||||
import { SnjsVersion } from './../Version'
|
import { SnjsVersion } from './../Version'
|
||||||
import { SNLog } from '../Log'
|
import { SNLog } from '../Log'
|
||||||
import { Challenge, ChallengeResponse, ListedClientInterface } from '../Services'
|
import { ChallengeResponse, ListedClientInterface } from '../Services'
|
||||||
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
|
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
|
||||||
import { ApplicationOptionsDefaults } from './Options/Defaults'
|
import { ApplicationOptionsDefaults } from './Options/Defaults'
|
||||||
|
|
||||||
@@ -112,6 +123,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
private apiService!: InternalServices.SNApiService
|
private apiService!: InternalServices.SNApiService
|
||||||
private declare userApiService: UserApiServiceInterface
|
private declare userApiService: UserApiServiceInterface
|
||||||
private declare userServer: UserServerInterface
|
private declare userServer: UserServerInterface
|
||||||
|
private declare userRequestServer: UserRequestServerInterface
|
||||||
private declare subscriptionApiService: SubscriptionApiServiceInterface
|
private declare subscriptionApiService: SubscriptionApiServiceInterface
|
||||||
private declare subscriptionServer: SubscriptionServerInterface
|
private declare subscriptionServer: SubscriptionServerInterface
|
||||||
private declare subscriptionManager: SubscriptionClientInterface
|
private declare subscriptionManager: SubscriptionClientInterface
|
||||||
@@ -132,7 +144,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
private keyRecoveryService!: InternalServices.SNKeyRecoveryService
|
private keyRecoveryService!: InternalServices.SNKeyRecoveryService
|
||||||
private preferencesService!: InternalServices.SNPreferencesService
|
private preferencesService!: InternalServices.SNPreferencesService
|
||||||
private featuresService!: InternalServices.SNFeaturesService
|
private featuresService!: InternalServices.SNFeaturesService
|
||||||
private userService!: InternalServices.UserService
|
private userService!: UserService
|
||||||
private webSocketsService!: InternalServices.SNWebSocketsService
|
private webSocketsService!: InternalServices.SNWebSocketsService
|
||||||
private settingsService!: InternalServices.SNSettingsService
|
private settingsService!: InternalServices.SNSettingsService
|
||||||
private mfaService!: InternalServices.SNMfaService
|
private mfaService!: InternalServices.SNMfaService
|
||||||
@@ -235,7 +247,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return this.itemManager
|
return this.itemManager
|
||||||
}
|
}
|
||||||
|
|
||||||
public get protections(): InternalServices.ProtectionsClientInterface {
|
public get protections(): ProtectionsClientInterface {
|
||||||
return this.protectionService
|
return this.protectionService
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +267,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return this.mutatorService
|
return this.mutatorService
|
||||||
}
|
}
|
||||||
|
|
||||||
public get sessions(): InternalServices.SessionsClientInterface {
|
public get sessions(): SessionsClientInterface {
|
||||||
return this.sessionManager
|
return this.sessionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,8 +359,8 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
await this.diskStorageService.decryptStorage()
|
await this.diskStorageService.decryptStorage()
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
void this.alertService.alert(
|
void this.alertService.alert(
|
||||||
InternalServices.ErrorAlertStrings.StorageDecryptErrorBody,
|
ErrorAlertStrings.StorageDecryptErrorBody,
|
||||||
InternalServices.ErrorAlertStrings.StorageDecryptErrorTitle,
|
ErrorAlertStrings.StorageDecryptErrorTitle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,12 +640,12 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
const result = await this.userService.performProtocolUpgrade()
|
const result = await this.userService.performProtocolUpgrade()
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
if (this.hasAccount()) {
|
if (this.hasAccount()) {
|
||||||
void this.alertService.alert(InternalServices.ProtocolUpgradeStrings.SuccessAccount)
|
void this.alertService.alert(ProtocolUpgradeStrings.SuccessAccount)
|
||||||
} else {
|
} else {
|
||||||
void this.alertService.alert(InternalServices.ProtocolUpgradeStrings.SuccessPasscodeOnly)
|
void this.alertService.alert(ProtocolUpgradeStrings.SuccessPasscodeOnly)
|
||||||
}
|
}
|
||||||
} else if (result.error) {
|
} else if (result.error) {
|
||||||
void this.alertService.alert(InternalServices.ProtocolUpgradeStrings.Fail)
|
void this.alertService.alert(ProtocolUpgradeStrings.Fail)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -848,7 +860,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
currentPassword: string,
|
currentPassword: string,
|
||||||
passcode?: string,
|
passcode?: string,
|
||||||
origination = Common.KeyParamsOrigination.EmailChange,
|
origination = Common.KeyParamsOrigination.EmailChange,
|
||||||
): Promise<InternalServices.CredentialsChangeFunctionResponse> {
|
): Promise<CredentialsChangeFunctionResponse> {
|
||||||
return this.userService.changeCredentials({
|
return this.userService.changeCredentials({
|
||||||
currentPassword,
|
currentPassword,
|
||||||
newEmail,
|
newEmail,
|
||||||
@@ -864,7 +876,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
passcode?: string,
|
passcode?: string,
|
||||||
origination = Common.KeyParamsOrigination.PasswordChange,
|
origination = Common.KeyParamsOrigination.PasswordChange,
|
||||||
validateNewPasswordStrength = true,
|
validateNewPasswordStrength = true,
|
||||||
): Promise<InternalServices.CredentialsChangeFunctionResponse> {
|
): Promise<CredentialsChangeFunctionResponse> {
|
||||||
return this.userService.changeCredentials({
|
return this.userService.changeCredentials({
|
||||||
currentPassword,
|
currentPassword,
|
||||||
newPassword,
|
newPassword,
|
||||||
@@ -886,7 +898,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
/** Keep a reference to the soon-to-be-cleared alertService */
|
/** Keep a reference to the soon-to-be-cleared alertService */
|
||||||
const alertService = this.alertService
|
const alertService = this.alertService
|
||||||
await this.user.signOut(true)
|
await this.user.signOut(true)
|
||||||
void alertService.alert(InternalServices.SessionStrings.CurrentSessionRevoked)
|
void alertService.alert(SessionStrings.CurrentSessionRevoked)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async validateAccountPassword(password: string): Promise<boolean> {
|
public async validateAccountPassword(password: string): Promise<boolean> {
|
||||||
@@ -1064,6 +1076,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.createApiService()
|
this.createApiService()
|
||||||
this.createHttpService()
|
this.createHttpService()
|
||||||
this.createUserServer()
|
this.createUserServer()
|
||||||
|
this.createUserRequestServer()
|
||||||
this.createUserApiService()
|
this.createUserApiService()
|
||||||
this.createSubscriptionServer()
|
this.createSubscriptionServer()
|
||||||
this.createSubscriptionApiService()
|
this.createSubscriptionApiService()
|
||||||
@@ -1111,6 +1124,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
;(this.apiService as unknown) = undefined
|
;(this.apiService as unknown) = undefined
|
||||||
;(this.userApiService as unknown) = undefined
|
;(this.userApiService as unknown) = undefined
|
||||||
;(this.userServer as unknown) = undefined
|
;(this.userServer as unknown) = undefined
|
||||||
|
;(this.userRequestServer as unknown) = undefined
|
||||||
;(this.subscriptionApiService as unknown) = undefined
|
;(this.subscriptionApiService as unknown) = undefined
|
||||||
;(this.subscriptionServer as unknown) = undefined
|
;(this.subscriptionServer as unknown) = undefined
|
||||||
;(this.subscriptionManager as unknown) = undefined
|
;(this.subscriptionManager as unknown) = undefined
|
||||||
@@ -1261,7 +1275,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createUserService(): void {
|
private createUserService(): void {
|
||||||
this.userService = new InternalServices.UserService(
|
this.userService = new UserService(
|
||||||
this.sessionManager,
|
this.sessionManager,
|
||||||
this.syncService,
|
this.syncService,
|
||||||
this.diskStorageService,
|
this.diskStorageService,
|
||||||
@@ -1270,17 +1284,17 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.alertService,
|
this.alertService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.protectionService,
|
this.protectionService,
|
||||||
this.apiService,
|
this.userApiService,
|
||||||
this.internalEventBus,
|
this.internalEventBus,
|
||||||
)
|
)
|
||||||
this.serviceObservers.push(
|
this.serviceObservers.push(
|
||||||
this.userService.addEventObserver(async (event, data) => {
|
this.userService.addEventObserver(async (event, data) => {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case InternalServices.AccountEvent.SignedInOrRegistered: {
|
case AccountEvent.SignedInOrRegistered: {
|
||||||
void this.notifyEvent(ApplicationEvent.SignedIn)
|
void this.notifyEvent(ApplicationEvent.SignedIn)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case InternalServices.AccountEvent.SignedOut: {
|
case AccountEvent.SignedOut: {
|
||||||
await this.notifyEvent(ApplicationEvent.SignedOut)
|
await this.notifyEvent(ApplicationEvent.SignedOut)
|
||||||
await this.prepareForDeinit()
|
await this.prepareForDeinit()
|
||||||
this.deinit(this.getDeinitMode(), data?.source || DeinitSource.SignOut)
|
this.deinit(this.getDeinitMode(), data?.source || DeinitSource.SignOut)
|
||||||
@@ -1308,13 +1322,17 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createUserApiService() {
|
private createUserApiService() {
|
||||||
this.userApiService = new UserApiService(this.userServer)
|
this.userApiService = new UserApiService(this.userServer, this.userRequestServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private createUserServer() {
|
private createUserServer() {
|
||||||
this.userServer = new UserServer(this.httpService)
|
this.userServer = new UserServer(this.httpService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createUserRequestServer() {
|
||||||
|
this.userRequestServer = new UserRequestServer(this.httpService)
|
||||||
|
}
|
||||||
|
|
||||||
private createSubscriptionApiService() {
|
private createSubscriptionApiService() {
|
||||||
this.subscriptionApiService = new SubscriptionApiService(this.subscriptionServer)
|
this.subscriptionApiService = new SubscriptionApiService(this.subscriptionServer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { InfoStrings } from '../Strings/Info'
|
|
||||||
import { NoteType } from '@standardnotes/features'
|
import { NoteType } from '@standardnotes/features'
|
||||||
|
import { InfoStrings } from '@standardnotes/services'
|
||||||
import {
|
import {
|
||||||
NoteMutator,
|
NoteMutator,
|
||||||
SNNote,
|
SNNote,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { AnyKeyParamsContent } from '@standardnotes/common'
|
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||||
import { SNLog } from '@Lib/Log'
|
import { SNLog } from '@Lib/Log'
|
||||||
import { EncryptedPayload, EncryptedTransferPayload, isErrorDecryptingPayload } from '@standardnotes/models'
|
import { EncryptedPayload, EncryptedTransferPayload, isErrorDecryptingPayload } from '@standardnotes/models'
|
||||||
import { Challenge } from '../Services/Challenge'
|
|
||||||
import { KeychainRecoveryStrings, SessionStrings } from '../Services/Api/Messages'
|
|
||||||
import { PreviousSnjsVersion1_0_0, PreviousSnjsVersion2_0_0, SnjsVersion } from '../Version'
|
import { PreviousSnjsVersion1_0_0, PreviousSnjsVersion2_0_0, SnjsVersion } from '../Version'
|
||||||
import { Migration } from '@Lib/Migrations/Migration'
|
import { Migration } from '@Lib/Migrations/Migration'
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +10,9 @@ import {
|
|||||||
ChallengeValidation,
|
ChallengeValidation,
|
||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
|
KeychainRecoveryStrings,
|
||||||
|
SessionStrings,
|
||||||
|
Challenge,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { isNullOrUndefined } from '@standardnotes/utils'
|
import { isNullOrUndefined } from '@standardnotes/utils'
|
||||||
import { CreateReader } from './StorageReaders/Functions'
|
import { CreateReader } from './StorageReaders/Functions'
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { Challenge } from '../Services/Challenge'
|
|
||||||
import { MigrationServices } from './MigrationServices'
|
import { MigrationServices } from './MigrationServices'
|
||||||
import { ApplicationStage, ChallengeValidation, ChallengeReason, ChallengePrompt } from '@standardnotes/services'
|
import {
|
||||||
|
ApplicationStage,
|
||||||
|
ChallengeValidation,
|
||||||
|
ChallengeReason,
|
||||||
|
ChallengePrompt,
|
||||||
|
Challenge,
|
||||||
|
} from '@standardnotes/services'
|
||||||
|
|
||||||
type StageHandler = () => Promise<void>
|
type StageHandler = () => Promise<void>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { SNRootKey } from '@standardnotes/encryption'
|
import { SNRootKey } from '@standardnotes/encryption'
|
||||||
import { Challenge, ChallengeService } from '../Challenge'
|
import { ChallengeService } from '../Challenge'
|
||||||
import { ListedService } from '../Listed/ListedService'
|
import { ListedService } from '../Listed/ListedService'
|
||||||
import { ActionResponse, HttpResponse } from '@standardnotes/responses'
|
import { ActionResponse, HttpResponse } from '@standardnotes/responses'
|
||||||
import { ContentType } from '@standardnotes/common'
|
import { ContentType } from '@standardnotes/common'
|
||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
EncryptionService,
|
EncryptionService,
|
||||||
|
Challenge,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,28 +13,44 @@ import {
|
|||||||
MetaReceivedData,
|
MetaReceivedData,
|
||||||
DiagnosticInfo,
|
DiagnosticInfo,
|
||||||
KeyValueStoreInterface,
|
KeyValueStoreInterface,
|
||||||
|
API_MESSAGE_GENERIC_SYNC_FAIL,
|
||||||
|
API_MESSAGE_GENERIC_TOKEN_REFRESH_FAIL,
|
||||||
|
API_MESSAGE_CHANGE_CREDENTIALS_IN_PROGRESS,
|
||||||
|
API_MESSAGE_FAILED_ACCESS_PURCHASE,
|
||||||
|
API_MESSAGE_FAILED_CREATE_FILE_TOKEN,
|
||||||
|
API_MESSAGE_FAILED_DELETE_REVISION,
|
||||||
|
API_MESSAGE_FAILED_GET_SETTINGS,
|
||||||
|
API_MESSAGE_FAILED_LISTED_REGISTRATION,
|
||||||
|
API_MESSAGE_FAILED_OFFLINE_ACTIVATION,
|
||||||
|
API_MESSAGE_FAILED_OFFLINE_FEATURES,
|
||||||
|
API_MESSAGE_FAILED_SUBSCRIPTION_INFO,
|
||||||
|
API_MESSAGE_FAILED_UPDATE_SETTINGS,
|
||||||
|
API_MESSAGE_GENERIC_CHANGE_CREDENTIALS_FAIL,
|
||||||
|
API_MESSAGE_GENERIC_INTEGRITY_CHECK_FAIL,
|
||||||
|
API_MESSAGE_GENERIC_INVALID_LOGIN,
|
||||||
|
API_MESSAGE_GENERIC_SINGLE_ITEM_SYNC_FAIL,
|
||||||
|
API_MESSAGE_INVALID_SESSION,
|
||||||
|
API_MESSAGE_LOGIN_IN_PROGRESS,
|
||||||
|
API_MESSAGE_TOKEN_REFRESH_IN_PROGRESS,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { FilesApiInterface } from '@standardnotes/files'
|
import { FilesApiInterface } from '@standardnotes/files'
|
||||||
|
|
||||||
import { ServerSyncPushContextualPayload, SNFeatureRepo, FileContent } from '@standardnotes/models'
|
import { ServerSyncPushContextualPayload, SNFeatureRepo, FileContent } from '@standardnotes/models'
|
||||||
import * as Responses from '@standardnotes/responses'
|
import * as Responses from '@standardnotes/responses'
|
||||||
import { API_MESSAGE_FAILED_OFFLINE_ACTIVATION } from '@Lib/Services/Api/Messages'
|
|
||||||
import { HttpParams, HttpRequest, HttpVerb, SNHttpService } from './HttpService'
|
import { HttpParams, HttpRequest, HttpVerb, SNHttpService } from './HttpService'
|
||||||
import { isUrlFirstParty, TRUSTED_FEATURE_HOSTS } from '@Lib/Hosts'
|
import { isUrlFirstParty, TRUSTED_FEATURE_HOSTS } from '@Lib/Hosts'
|
||||||
import { Paths } from './Paths'
|
import { Paths } from './Paths'
|
||||||
import { Session } from '../Session/Sessions/Session'
|
import { Session } from '../Session/Sessions/Session'
|
||||||
import { TokenSession } from '../Session/Sessions/TokenSession'
|
import { TokenSession } from '../Session/Sessions/TokenSession'
|
||||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||||
import { UserServerInterface } from '../User/UserServerInterface'
|
import { HttpResponseMeta } from '@standardnotes/api'
|
||||||
import { UuidString } from '../../Types/UuidString'
|
import { UuidString } from '../../Types/UuidString'
|
||||||
import * as messages from '@Lib/Services/Api/Messages'
|
|
||||||
import merge from 'lodash/merge'
|
import merge from 'lodash/merge'
|
||||||
import { SettingsServerInterface } from '../Settings/SettingsServerInterface'
|
import { SettingsServerInterface } from '../Settings/SettingsServerInterface'
|
||||||
import { Strings } from '@Lib/Strings'
|
import { Strings } from '@Lib/Strings'
|
||||||
import { SNRootKeyParams } from '@standardnotes/encryption'
|
import { SNRootKeyParams } from '@standardnotes/encryption'
|
||||||
import { ApiEndpointParam, ClientDisplayableError, CreateValetTokenPayload } from '@standardnotes/responses'
|
import { ApiEndpointParam, ClientDisplayableError, CreateValetTokenPayload } from '@standardnotes/responses'
|
||||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||||
import { HttpResponseMeta } from '@standardnotes/api'
|
|
||||||
|
|
||||||
/** Legacy api version field to be specified in params when calling v0 APIs. */
|
/** Legacy api version field to be specified in params when calling v0 APIs. */
|
||||||
const V0_API_VERSION = '20200115'
|
const V0_API_VERSION = '20200115'
|
||||||
@@ -48,7 +64,6 @@ export class SNApiService
|
|||||||
FilesApiInterface,
|
FilesApiInterface,
|
||||||
IntegrityApiInterface,
|
IntegrityApiInterface,
|
||||||
ItemsServerInterface,
|
ItemsServerInterface,
|
||||||
UserServerInterface,
|
|
||||||
SettingsServerInterface
|
SettingsServerInterface
|
||||||
{
|
{
|
||||||
private session?: Session
|
private session?: Session
|
||||||
@@ -232,7 +247,7 @@ export class SNApiService
|
|||||||
return this.request({
|
return this.request({
|
||||||
verb: HttpVerb.Post,
|
verb: HttpVerb.Post,
|
||||||
url: joinPaths(this.host, Paths.v2.keyParams),
|
url: joinPaths(this.host, Paths.v2.keyParams),
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_GENERIC_INVALID_LOGIN,
|
fallbackErrorMessage: API_MESSAGE_GENERIC_INVALID_LOGIN,
|
||||||
params,
|
params,
|
||||||
/** A session is optional here, if valid, endpoint bypasses 2FA and returns additional params */
|
/** A session is optional here, if valid, endpoint bypasses 2FA and returns additional params */
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
@@ -245,7 +260,7 @@ export class SNApiService
|
|||||||
ephemeral: boolean
|
ephemeral: boolean
|
||||||
}): Promise<Responses.SignInResponse | Responses.HttpResponse> {
|
}): Promise<Responses.SignInResponse | Responses.HttpResponse> {
|
||||||
if (this.authenticating) {
|
if (this.authenticating) {
|
||||||
return this.createErrorResponse(messages.API_MESSAGE_LOGIN_IN_PROGRESS) as Responses.SignInResponse
|
return this.createErrorResponse(API_MESSAGE_LOGIN_IN_PROGRESS) as Responses.SignInResponse
|
||||||
}
|
}
|
||||||
this.authenticating = true
|
this.authenticating = true
|
||||||
const url = joinPaths(this.host, Paths.v2.signIn)
|
const url = joinPaths(this.host, Paths.v2.signIn)
|
||||||
@@ -260,7 +275,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Post,
|
verb: HttpVerb.Post,
|
||||||
url,
|
url,
|
||||||
params,
|
params,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_GENERIC_INVALID_LOGIN,
|
fallbackErrorMessage: API_MESSAGE_GENERIC_INVALID_LOGIN,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.authenticating = false
|
this.authenticating = false
|
||||||
@@ -285,7 +300,7 @@ export class SNApiService
|
|||||||
newEmail?: string
|
newEmail?: string
|
||||||
}): Promise<Responses.ChangeCredentialsResponse | Responses.HttpResponse> {
|
}): Promise<Responses.ChangeCredentialsResponse | Responses.HttpResponse> {
|
||||||
if (this.changing) {
|
if (this.changing) {
|
||||||
return this.createErrorResponse(messages.API_MESSAGE_CHANGE_CREDENTIALS_IN_PROGRESS)
|
return this.createErrorResponse(API_MESSAGE_CHANGE_CREDENTIALS_IN_PROGRESS)
|
||||||
}
|
}
|
||||||
const preprocessingError = this.preprocessingError()
|
const preprocessingError = this.preprocessingError()
|
||||||
if (preprocessingError) {
|
if (preprocessingError) {
|
||||||
@@ -309,10 +324,7 @@ export class SNApiService
|
|||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_CHANGE_CREDENTIALS_FAIL)
|
||||||
errorResponse,
|
|
||||||
messages.API_MESSAGE_GENERIC_CHANGE_CREDENTIALS_FAIL,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
@@ -321,17 +333,6 @@ export class SNApiService
|
|||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deleteAccount(userUuid: string): Promise<Responses.HttpResponse | Responses.MinimalHttpResponse> {
|
|
||||||
const url = joinPaths(this.host, Paths.v1.deleteAccount(userUuid))
|
|
||||||
const response = await this.request({
|
|
||||||
verb: HttpVerb.Delete,
|
|
||||||
url,
|
|
||||||
authentication: this.session?.authorizationValue,
|
|
||||||
fallbackErrorMessage: messages.ServerErrorStrings.DeleteAccountError,
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync(
|
async sync(
|
||||||
payloads: ServerSyncPushContextualPayload[],
|
payloads: ServerSyncPushContextualPayload[],
|
||||||
lastSyncToken: string,
|
lastSyncToken: string,
|
||||||
@@ -360,7 +361,7 @@ export class SNApiService
|
|||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
})
|
})
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
|
|
||||||
@@ -405,7 +406,7 @@ export class SNApiService
|
|||||||
})
|
})
|
||||||
.catch((errorResponse) => {
|
.catch((errorResponse) => {
|
||||||
this.preprocessAuthenticatedErrorResponse(errorResponse)
|
this.preprocessAuthenticatedErrorResponse(errorResponse)
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_TOKEN_REFRESH_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_TOKEN_REFRESH_FAIL)
|
||||||
})
|
})
|
||||||
this.refreshingSession = false
|
this.refreshingSession = false
|
||||||
return result
|
return result
|
||||||
@@ -427,7 +428,7 @@ export class SNApiService
|
|||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
})
|
})
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
|
|
||||||
@@ -451,7 +452,7 @@ export class SNApiService
|
|||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
})
|
})
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
return response
|
return response
|
||||||
@@ -473,7 +474,7 @@ export class SNApiService
|
|||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
})
|
})
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
return response
|
return response
|
||||||
@@ -498,7 +499,7 @@ export class SNApiService
|
|||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
})
|
})
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
return response
|
return response
|
||||||
@@ -516,7 +517,7 @@ export class SNApiService
|
|||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.errorResponseWithFallbackMessage(errorResponse, messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
})
|
})
|
||||||
this.processResponse(response)
|
this.processResponse(response)
|
||||||
return response
|
return response
|
||||||
@@ -546,7 +547,7 @@ export class SNApiService
|
|||||||
return await this.tokenRefreshableRequest<Responses.ListSettingsResponse>({
|
return await this.tokenRefreshableRequest<Responses.ListSettingsResponse>({
|
||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url: joinPaths(this.host, Paths.v1.settings(userUuid)),
|
url: joinPaths(this.host, Paths.v1.settings(userUuid)),
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_GET_SETTINGS,
|
fallbackErrorMessage: API_MESSAGE_FAILED_GET_SETTINGS,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -566,7 +567,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Put,
|
verb: HttpVerb.Put,
|
||||||
url: joinPaths(this.host, Paths.v1.settings(userUuid)),
|
url: joinPaths(this.host, Paths.v1.settings(userUuid)),
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_UPDATE_SETTINGS,
|
fallbackErrorMessage: API_MESSAGE_FAILED_UPDATE_SETTINGS,
|
||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -576,7 +577,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName.toLowerCase() as SettingName)),
|
url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName.toLowerCase() as SettingName)),
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_GET_SETTINGS,
|
fallbackErrorMessage: API_MESSAGE_FAILED_GET_SETTINGS,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,7 +592,7 @@ export class SNApiService
|
|||||||
Paths.v1.subscriptionSetting(userUuid, settingName.toLowerCase() as SubscriptionSettingName),
|
Paths.v1.subscriptionSetting(userUuid, settingName.toLowerCase() as SubscriptionSettingName),
|
||||||
),
|
),
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_GET_SETTINGS,
|
fallbackErrorMessage: API_MESSAGE_FAILED_GET_SETTINGS,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,7 +601,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Delete,
|
verb: HttpVerb.Delete,
|
||||||
url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName)),
|
url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName)),
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_UPDATE_SETTINGS,
|
fallbackErrorMessage: API_MESSAGE_FAILED_UPDATE_SETTINGS,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,7 +613,7 @@ export class SNApiService
|
|||||||
const response = await this.tokenRefreshableRequest({
|
const response = await this.tokenRefreshableRequest({
|
||||||
verb: HttpVerb.Delete,
|
verb: HttpVerb.Delete,
|
||||||
url,
|
url,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_DELETE_REVISION,
|
fallbackErrorMessage: API_MESSAGE_FAILED_DELETE_REVISION,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
})
|
})
|
||||||
return response
|
return response
|
||||||
@@ -623,7 +624,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url,
|
url,
|
||||||
external: true,
|
external: true,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_GENERIC_INVALID_LOGIN,
|
fallbackErrorMessage: API_MESSAGE_GENERIC_INVALID_LOGIN,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,7 +634,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url,
|
url,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_SUBSCRIPTION_INFO,
|
fallbackErrorMessage: API_MESSAGE_FAILED_SUBSCRIPTION_INFO,
|
||||||
})
|
})
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
@@ -645,7 +646,7 @@ export class SNApiService
|
|||||||
const response = await this.request({
|
const response = await this.request({
|
||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url,
|
url,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_SUBSCRIPTION_INFO,
|
fallbackErrorMessage: API_MESSAGE_FAILED_SUBSCRIPTION_INFO,
|
||||||
})
|
})
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
@@ -656,7 +657,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Post,
|
verb: HttpVerb.Post,
|
||||||
url,
|
url,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_ACCESS_PURCHASE,
|
fallbackErrorMessage: API_MESSAGE_FAILED_ACCESS_PURCHASE,
|
||||||
})
|
})
|
||||||
return (response as Responses.PostSubscriptionTokensResponse).data?.token
|
return (response as Responses.PostSubscriptionTokensResponse).data?.token
|
||||||
}
|
}
|
||||||
@@ -680,7 +681,7 @@ export class SNApiService
|
|||||||
const response: Responses.HttpResponse | Responses.GetOfflineFeaturesResponse = await this.request({
|
const response: Responses.HttpResponse | Responses.GetOfflineFeaturesResponse = await this.request({
|
||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url: featuresUrl,
|
url: featuresUrl,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_OFFLINE_FEATURES,
|
fallbackErrorMessage: API_MESSAGE_FAILED_OFFLINE_FEATURES,
|
||||||
customHeaders: [{ key: 'x-offline-token', value: extensionKey }],
|
customHeaders: [{ key: 'x-offline-token', value: extensionKey }],
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -702,7 +703,7 @@ export class SNApiService
|
|||||||
return await this.tokenRefreshableRequest<Responses.ListedRegistrationResponse>({
|
return await this.tokenRefreshableRequest<Responses.ListedRegistrationResponse>({
|
||||||
verb: HttpVerb.Post,
|
verb: HttpVerb.Post,
|
||||||
url: joinPaths(this.host, Paths.v1.listedRegistration(this.user.uuid)),
|
url: joinPaths(this.host, Paths.v1.listedRegistration(this.user.uuid)),
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_LISTED_REGISTRATION,
|
fallbackErrorMessage: API_MESSAGE_FAILED_LISTED_REGISTRATION,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -723,7 +724,7 @@ export class SNApiService
|
|||||||
verb: HttpVerb.Post,
|
verb: HttpVerb.Post,
|
||||||
url: url,
|
url: url,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_FAILED_CREATE_FILE_TOKEN,
|
fallbackErrorMessage: API_MESSAGE_FAILED_CREATE_FILE_TOKEN,
|
||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -856,7 +857,7 @@ export class SNApiService
|
|||||||
params: {
|
params: {
|
||||||
integrityPayloads,
|
integrityPayloads,
|
||||||
},
|
},
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_GENERIC_INTEGRITY_CHECK_FAIL,
|
fallbackErrorMessage: API_MESSAGE_GENERIC_INTEGRITY_CHECK_FAIL,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -865,17 +866,17 @@ export class SNApiService
|
|||||||
return await this.tokenRefreshableRequest<Responses.GetSingleItemResponse>({
|
return await this.tokenRefreshableRequest<Responses.GetSingleItemResponse>({
|
||||||
verb: HttpVerb.Get,
|
verb: HttpVerb.Get,
|
||||||
url: joinPaths(this.host, Paths.v1.getSingleItem(itemUuid)),
|
url: joinPaths(this.host, Paths.v1.getSingleItem(itemUuid)),
|
||||||
fallbackErrorMessage: messages.API_MESSAGE_GENERIC_SINGLE_ITEM_SYNC_FAIL,
|
fallbackErrorMessage: API_MESSAGE_GENERIC_SINGLE_ITEM_SYNC_FAIL,
|
||||||
authentication: this.session?.authorizationValue,
|
authentication: this.session?.authorizationValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private preprocessingError() {
|
private preprocessingError() {
|
||||||
if (this.refreshingSession) {
|
if (this.refreshingSession) {
|
||||||
return this.createErrorResponse(messages.API_MESSAGE_TOKEN_REFRESH_IN_PROGRESS)
|
return this.createErrorResponse(API_MESSAGE_TOKEN_REFRESH_IN_PROGRESS)
|
||||||
}
|
}
|
||||||
if (!this.session) {
|
if (!this.session) {
|
||||||
return this.createErrorResponse(messages.API_MESSAGE_INVALID_SESSION)
|
return this.createErrorResponse(API_MESSAGE_INVALID_SESSION)
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { API_MESSAGE_RATE_LIMITED, UNKNOWN_ERROR } from './Messages'
|
|
||||||
import { HttpResponse, StatusCode } from '@standardnotes/responses'
|
import { HttpResponse, StatusCode } from '@standardnotes/responses'
|
||||||
import { isString } from '@standardnotes/utils'
|
import { isString } from '@standardnotes/utils'
|
||||||
import { SnjsVersion } from '@Lib/Version'
|
import { SnjsVersion } from '@Lib/Version'
|
||||||
import { AbstractService, InternalEventBusInterface } from '@standardnotes/services'
|
import {
|
||||||
|
AbstractService,
|
||||||
|
API_MESSAGE_RATE_LIMITED,
|
||||||
|
InternalEventBusInterface,
|
||||||
|
UNKNOWN_ERROR,
|
||||||
|
} from '@standardnotes/services'
|
||||||
import { Environment } from '@standardnotes/models'
|
import { Environment } from '@standardnotes/models'
|
||||||
|
|
||||||
export enum HttpVerb {
|
export enum HttpVerb {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export * from './ApiService'
|
export * from './ApiService'
|
||||||
export * from './HttpService'
|
export * from './HttpService'
|
||||||
export * from './Messages'
|
|
||||||
export * from './Paths'
|
export * from './Paths'
|
||||||
export * from '../Session/Sessions/Session'
|
export * from '../Session/Sessions/Session'
|
||||||
export * from '../Session/SessionManager'
|
export * from '../Session/SessionManager'
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Challenge } from './Challenge'
|
import { Challenge, ChallengeValue, ChallengeArtifacts } from '@standardnotes/services'
|
||||||
import { ChallengeResponse } from './ChallengeResponse'
|
import { ChallengeResponse } from './ChallengeResponse'
|
||||||
import { removeFromArray } from '@standardnotes/utils'
|
import { removeFromArray } from '@standardnotes/utils'
|
||||||
import { ValueCallback } from './ChallengeService'
|
import { ValueCallback } from './ChallengeService'
|
||||||
import { ChallengeValue, ChallengeArtifacts } from '@standardnotes/services'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A challenge operation stores user-submitted values and callbacks.
|
* A challenge operation stores user-submitted values and callbacks.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { isNullOrUndefined } from '@standardnotes/utils'
|
import { isNullOrUndefined } from '@standardnotes/utils'
|
||||||
import { Challenge } from './Challenge'
|
|
||||||
import {
|
import {
|
||||||
|
Challenge,
|
||||||
ChallengeResponseInterface,
|
ChallengeResponseInterface,
|
||||||
ChallengeValidation,
|
ChallengeValidation,
|
||||||
ChallengeValue,
|
ChallengeValue,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
AbstractService,
|
AbstractService,
|
||||||
ChallengeServiceInterface,
|
ChallengeServiceInterface,
|
||||||
InternalEventBusInterface,
|
InternalEventBusInterface,
|
||||||
|
Challenge,
|
||||||
ChallengeArtifacts,
|
ChallengeArtifacts,
|
||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
ChallengeValidation,
|
ChallengeValidation,
|
||||||
@@ -17,7 +18,6 @@ import {
|
|||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { ChallengeResponse } from './ChallengeResponse'
|
import { ChallengeResponse } from './ChallengeResponse'
|
||||||
import { ChallengeOperation } from './ChallengeOperation'
|
import { ChallengeOperation } from './ChallengeOperation'
|
||||||
import { Challenge } from './Challenge'
|
|
||||||
|
|
||||||
type ChallengeValidationResponse = {
|
type ChallengeValidationResponse = {
|
||||||
valid: boolean
|
valid: boolean
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './Challenge'
|
|
||||||
export * from './ChallengeOperation'
|
export * from './ChallengeOperation'
|
||||||
export * from './ChallengeResponse'
|
export * from './ChallengeResponse'
|
||||||
export * from './ChallengeService'
|
export * from './ChallengeService'
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
import { ItemInterface, SNComponent, SNFeatureRepo } from '@standardnotes/models'
|
import { ItemInterface, SNComponent, SNFeatureRepo } from '@standardnotes/models'
|
||||||
import { SNSyncService } from '../Sync/SyncService'
|
import { SNSyncService } from '../Sync/SyncService'
|
||||||
import { SettingName } from '@standardnotes/settings'
|
import { SettingName } from '@standardnotes/settings'
|
||||||
import {
|
|
||||||
ItemManager,
|
|
||||||
AlertService,
|
|
||||||
SNApiService,
|
|
||||||
UserService,
|
|
||||||
SNSessionManager,
|
|
||||||
DiskStorageService,
|
|
||||||
StorageKey,
|
|
||||||
} from '@Lib/index'
|
|
||||||
import { SNFeaturesService } from '@Lib/Services/Features'
|
import { SNFeaturesService } from '@Lib/Services/Features'
|
||||||
import { ContentType, RoleName } from '@standardnotes/common'
|
import { ContentType, RoleName } from '@standardnotes/common'
|
||||||
import { FeatureDescription, FeatureIdentifier, GetFeatures } from '@standardnotes/features'
|
import { FeatureDescription, FeatureIdentifier, GetFeatures } from '@standardnotes/features'
|
||||||
@@ -17,7 +8,16 @@ import { SNWebSocketsService } from '../Api/WebsocketsService'
|
|||||||
import { SNSettingsService } from '../Settings'
|
import { SNSettingsService } from '../Settings'
|
||||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||||
import { convertTimestampToMilliseconds } from '@standardnotes/utils'
|
import { convertTimestampToMilliseconds } from '@standardnotes/utils'
|
||||||
import { FeatureStatus, InternalEventBusInterface } from '@standardnotes/services'
|
import {
|
||||||
|
AlertService,
|
||||||
|
FeatureStatus,
|
||||||
|
InternalEventBusInterface,
|
||||||
|
StorageKey,
|
||||||
|
UserService,
|
||||||
|
} from '@standardnotes/services'
|
||||||
|
import { SNApiService, SNSessionManager } from '../Api'
|
||||||
|
import { ItemManager } from '../Items'
|
||||||
|
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||||
|
|
||||||
describe('featuresService', () => {
|
describe('featuresService', () => {
|
||||||
let storageService: DiskStorageService
|
let storageService: DiskStorageService
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { AccountEvent, UserService } from '../User/UserService'
|
|
||||||
import { SNApiService } from '../Api/ApiService'
|
import { SNApiService } from '../Api/ApiService'
|
||||||
import {
|
import {
|
||||||
arraysEqual,
|
arraysEqual,
|
||||||
@@ -24,12 +23,15 @@ import { TRUSTED_CUSTOM_EXTENSIONS_HOSTS, TRUSTED_FEATURE_HOSTS } from '@Lib/Hos
|
|||||||
import { UserRolesChangedEvent } from '@standardnotes/domain-events'
|
import { UserRolesChangedEvent } from '@standardnotes/domain-events'
|
||||||
import { UuidString } from '@Lib/Types/UuidString'
|
import { UuidString } from '@Lib/Types/UuidString'
|
||||||
import * as FeaturesImports from '@standardnotes/features'
|
import * as FeaturesImports from '@standardnotes/features'
|
||||||
import * as Messages from '@Lib/Services/Api/Messages'
|
|
||||||
import * as Models from '@standardnotes/models'
|
import * as Models from '@standardnotes/models'
|
||||||
import {
|
import {
|
||||||
AbstractService,
|
AbstractService,
|
||||||
|
AccountEvent,
|
||||||
AlertService,
|
AlertService,
|
||||||
ApiServiceEvent,
|
ApiServiceEvent,
|
||||||
|
API_MESSAGE_FAILED_DOWNLOADING_EXTENSION,
|
||||||
|
API_MESSAGE_FAILED_OFFLINE_ACTIVATION,
|
||||||
|
API_MESSAGE_UNTRUSTED_EXTENSIONS_WARNING,
|
||||||
ApplicationStage,
|
ApplicationStage,
|
||||||
ButtonType,
|
ButtonType,
|
||||||
DiagnosticInfo,
|
DiagnosticInfo,
|
||||||
@@ -39,10 +41,12 @@ import {
|
|||||||
InternalEventBusInterface,
|
InternalEventBusInterface,
|
||||||
InternalEventHandlerInterface,
|
InternalEventHandlerInterface,
|
||||||
InternalEventInterface,
|
InternalEventInterface,
|
||||||
|
INVALID_EXTENSION_URL,
|
||||||
MetaReceivedData,
|
MetaReceivedData,
|
||||||
OfflineSubscriptionEntitlements,
|
OfflineSubscriptionEntitlements,
|
||||||
SetOfflineFeaturesFunctionResponse,
|
SetOfflineFeaturesFunctionResponse,
|
||||||
StorageKey,
|
StorageKey,
|
||||||
|
UserService,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { FeatureIdentifier } from '@standardnotes/features'
|
import { FeatureIdentifier } from '@standardnotes/features'
|
||||||
|
|
||||||
@@ -250,7 +254,7 @@ export class SNFeaturesService
|
|||||||
void this.syncService.sync()
|
void this.syncService.sync()
|
||||||
return this.downloadOfflineFeatures(offlineRepo)
|
return this.downloadOfflineFeatures(offlineRepo)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return new ClientDisplayableError(Messages.API_MESSAGE_FAILED_OFFLINE_ACTIVATION)
|
return new ClientDisplayableError(API_MESSAGE_FAILED_OFFLINE_ACTIVATION)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +284,7 @@ export class SNFeaturesService
|
|||||||
extensionKey,
|
extensionKey,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new ClientDisplayableError(Messages.API_MESSAGE_FAILED_OFFLINE_ACTIVATION)
|
return new ClientDisplayableError(API_MESSAGE_FAILED_OFFLINE_ACTIVATION)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,7 +635,7 @@ export class SNFeaturesService
|
|||||||
const { host } = new URL(url)
|
const { host } = new URL(url)
|
||||||
if (!trustedCustomExtensionsUrls.includes(host)) {
|
if (!trustedCustomExtensionsUrls.includes(host)) {
|
||||||
const didConfirm = await this.alertService.confirm(
|
const didConfirm = await this.alertService.confirm(
|
||||||
Messages.API_MESSAGE_UNTRUSTED_EXTENSIONS_WARNING,
|
API_MESSAGE_UNTRUSTED_EXTENSIONS_WARNING,
|
||||||
'Install extension from an untrusted source?',
|
'Install extension from an untrusted source?',
|
||||||
'Proceed to install',
|
'Proceed to install',
|
||||||
ButtonType.Danger,
|
ButtonType.Danger,
|
||||||
@@ -644,7 +648,7 @@ export class SNFeaturesService
|
|||||||
return this.performDownloadExternalFeature(url)
|
return this.performDownloadExternalFeature(url)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
void this.alertService.alert(Messages.INVALID_EXTENSION_URL)
|
void this.alertService.alert(INVALID_EXTENSION_URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
@@ -653,7 +657,7 @@ export class SNFeaturesService
|
|||||||
private async performDownloadExternalFeature(url: string): Promise<Models.SNComponent | undefined> {
|
private async performDownloadExternalFeature(url: string): Promise<Models.SNComponent | undefined> {
|
||||||
const response = await this.apiService.downloadFeatureUrl(url)
|
const response = await this.apiService.downloadFeatureUrl(url)
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
await this.alertService.alert(Messages.API_MESSAGE_FAILED_DOWNLOADING_EXTENSION)
|
await this.alertService.alert(API_MESSAGE_FAILED_DOWNLOADING_EXTENSION)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,14 +687,14 @@ export class SNFeaturesService
|
|||||||
|
|
||||||
const nativeFeature = FeaturesImports.FindNativeFeature(rawFeature.identifier)
|
const nativeFeature = FeaturesImports.FindNativeFeature(rawFeature.identifier)
|
||||||
if (nativeFeature) {
|
if (nativeFeature) {
|
||||||
await this.alertService.alert(Messages.API_MESSAGE_FAILED_DOWNLOADING_EXTENSION)
|
await this.alertService.alert(API_MESSAGE_FAILED_DOWNLOADING_EXTENSION)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawFeature.url) {
|
if (rawFeature.url) {
|
||||||
for (const nativeFeature of FeaturesImports.GetFeatures()) {
|
for (const nativeFeature of FeaturesImports.GetFeatures()) {
|
||||||
if (rawFeature.url.includes(nativeFeature.identifier)) {
|
if (rawFeature.url.includes(nativeFeature.identifier)) {
|
||||||
await this.alertService.alert(Messages.API_MESSAGE_FAILED_DOWNLOADING_EXTENSION)
|
await this.alertService.alert(API_MESSAGE_FAILED_DOWNLOADING_EXTENSION)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { KeyRecoveryOperation } from './KeyRecoveryOperation'
|
import { KeyRecoveryOperation } from './KeyRecoveryOperation'
|
||||||
import { SNRootKeyParams, SNRootKey, KeyParamsFromApiResponse, KeyRecoveryStrings } from '@standardnotes/encryption'
|
import { SNRootKeyParams, SNRootKey, KeyParamsFromApiResponse, KeyRecoveryStrings } from '@standardnotes/encryption'
|
||||||
import { UserService } from '../User/UserService'
|
|
||||||
import {
|
import {
|
||||||
isErrorDecryptingPayload,
|
isErrorDecryptingPayload,
|
||||||
EncryptedPayloadInterface,
|
EncryptedPayloadInterface,
|
||||||
@@ -14,7 +13,7 @@ import {
|
|||||||
import { SNSyncService } from '../Sync/SyncService'
|
import { SNSyncService } from '../Sync/SyncService'
|
||||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||||
import { PayloadManager } from '../Payloads/PayloadManager'
|
import { PayloadManager } from '../Payloads/PayloadManager'
|
||||||
import { Challenge, ChallengeService } from '../Challenge'
|
import { ChallengeService } from '../Challenge'
|
||||||
import { SNApiService } from '@Lib/Services/Api/ApiService'
|
import { SNApiService } from '@Lib/Services/Api/ApiService'
|
||||||
import { ContentType, Uuid } from '@standardnotes/common'
|
import { ContentType, Uuid } from '@standardnotes/common'
|
||||||
import { ItemManager } from '../Items/ItemManager'
|
import { ItemManager } from '../Items/ItemManager'
|
||||||
@@ -32,6 +31,8 @@ import {
|
|||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
EncryptionService,
|
EncryptionService,
|
||||||
|
Challenge,
|
||||||
|
UserService,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import {
|
import {
|
||||||
UndecryptableItemsStorage,
|
UndecryptableItemsStorage,
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { SettingName } from '@standardnotes/settings'
|
import { SettingName } from '@standardnotes/settings'
|
||||||
|
|
||||||
import { SNSettingsService } from '../Settings'
|
import { SNSettingsService } from '../Settings'
|
||||||
import * as messages from '../Api/Messages'
|
|
||||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||||
import { SNFeaturesService } from '../Features/FeaturesService'
|
import { SNFeaturesService } from '../Features/FeaturesService'
|
||||||
import { FeatureIdentifier } from '@standardnotes/features'
|
import { FeatureIdentifier } from '@standardnotes/features'
|
||||||
import { AbstractService, InternalEventBusInterface } from '@standardnotes/services'
|
import { AbstractService, InternalEventBusInterface, SignInStrings } from '@standardnotes/services'
|
||||||
|
|
||||||
export class SNMfaService extends AbstractService {
|
export class SNMfaService extends AbstractService {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -38,7 +37,7 @@ export class SNMfaService extends AbstractService {
|
|||||||
const otpTokenValid = otpToken != undefined && otpToken === (await this.getOtpToken(secret))
|
const otpTokenValid = otpToken != undefined && otpToken === (await this.getOtpToken(secret))
|
||||||
|
|
||||||
if (!otpTokenValid) {
|
if (!otpTokenValid) {
|
||||||
throw new Error(messages.SignInStrings.IncorrectMfa)
|
throw new Error(SignInStrings.IncorrectMfa)
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.saveMfaSetting(secret)
|
return this.saveMfaSetting(secret)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
MutatorClientInterface,
|
MutatorClientInterface,
|
||||||
|
Challenge,
|
||||||
|
InfoStrings,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||||
@@ -18,7 +20,7 @@ import { SNProtectionService } from '../Protection/ProtectionService'
|
|||||||
import { SNSyncService } from '../Sync'
|
import { SNSyncService } from '../Sync'
|
||||||
import { Strings } from '../../Strings'
|
import { Strings } from '../../Strings'
|
||||||
import { TagsToFoldersMigrationApplicator } from '@Lib/Migrations/Applicators/TagsToFolders'
|
import { TagsToFoldersMigrationApplicator } from '@Lib/Migrations/Applicators/TagsToFolders'
|
||||||
import { Challenge, ChallengeService } from '../Challenge'
|
import { ChallengeService } from '../Challenge'
|
||||||
import {
|
import {
|
||||||
BackupFile,
|
BackupFile,
|
||||||
BackupFileDecryptedContextualPayload,
|
BackupFileDecryptedContextualPayload,
|
||||||
@@ -170,7 +172,13 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
|||||||
items: I[],
|
items: I[],
|
||||||
reason: ChallengeReason,
|
reason: ChallengeReason,
|
||||||
): Promise<I[] | undefined> {
|
): Promise<I[] | undefined> {
|
||||||
if (!(await this.protectionService.authorizeAction(reason))) {
|
if (
|
||||||
|
!(await this.protectionService.authorizeAction(reason, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
}))
|
||||||
|
) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,13 +322,13 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
|||||||
|
|
||||||
const supportedVersions = this.encryption.supportedVersions()
|
const supportedVersions = this.encryption.supportedVersions()
|
||||||
if (!supportedVersions.includes(version)) {
|
if (!supportedVersions.includes(version)) {
|
||||||
return { error: new ClientDisplayableError(Strings.Info.UnsupportedBackupFileVersion) }
|
return { error: new ClientDisplayableError(InfoStrings.UnsupportedBackupFileVersion) }
|
||||||
}
|
}
|
||||||
|
|
||||||
const userVersion = this.encryption.getUserVersion()
|
const userVersion = this.encryption.getUserVersion()
|
||||||
if (userVersion && compareVersions(version, userVersion) === 1) {
|
if (userVersion && compareVersions(version, userVersion) === 1) {
|
||||||
/** File was made with a greater version than the user's account */
|
/** File was made with a greater version than the user's account */
|
||||||
return { error: new ClientDisplayableError(Strings.Info.BackupFileMoreRecentThanAccount) }
|
return { error: new ClientDisplayableError(InfoStrings.BackupFileMoreRecentThanAccount) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Challenge } from './../Challenge/Challenge'
|
|
||||||
import { ChallengeService } from './../Challenge/ChallengeService'
|
import { ChallengeService } from './../Challenge/ChallengeService'
|
||||||
import { SNLog } from '@Lib/Log'
|
import { SNLog } from '@Lib/Log'
|
||||||
import { DecryptedItem } from '@standardnotes/models'
|
import { DecryptedItem } from '@standardnotes/models'
|
||||||
@@ -11,14 +10,16 @@ import {
|
|||||||
ApplicationStage,
|
ApplicationStage,
|
||||||
StorageKey,
|
StorageKey,
|
||||||
DiagnosticInfo,
|
DiagnosticInfo,
|
||||||
|
Challenge,
|
||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
ChallengePrompt,
|
ChallengePrompt,
|
||||||
ChallengeValidation,
|
ChallengeValidation,
|
||||||
EncryptionService,
|
EncryptionService,
|
||||||
|
MobileUnlockTiming,
|
||||||
|
TimingDisplayOption,
|
||||||
|
ProtectionsClientInterface,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { ProtectionsClientInterface } from './ClientInterface'
|
|
||||||
import { ContentType } from '@standardnotes/common'
|
import { ContentType } from '@standardnotes/common'
|
||||||
import { MobileUnlockTiming, TimingDisplayOption } from './MobileUnlockTiming'
|
|
||||||
|
|
||||||
export enum ProtectionEvent {
|
export enum ProtectionEvent {
|
||||||
UnprotectedSessionBegan = 'UnprotectedSessionBegan',
|
UnprotectedSessionBegan = 'UnprotectedSessionBegan',
|
||||||
@@ -176,62 +177,95 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
|||||||
item.content_type === ContentType.Note
|
item.content_type === ContentType.Note
|
||||||
? ChallengeReason.AccessProtectedNote
|
? ChallengeReason.AccessProtectedNote
|
||||||
: ChallengeReason.AccessProtectedFile,
|
: ChallengeReason.AccessProtectedFile,
|
||||||
|
{ fallBackToAccountPassword: true, requireAccountPassword: false, forcePrompt: false },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizeAddingPasscode(): Promise<boolean> {
|
authorizeAddingPasscode(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.AddPasscode)
|
return this.authorizeAction(ChallengeReason.AddPasscode, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizeChangingPasscode(): Promise<boolean> {
|
authorizeChangingPasscode(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.ChangePasscode)
|
return this.authorizeAction(ChallengeReason.ChangePasscode, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizeRemovingPasscode(): Promise<boolean> {
|
authorizeRemovingPasscode(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.RemovePasscode)
|
return this.authorizeAction(ChallengeReason.RemovePasscode, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizeSearchingProtectedNotesText(): Promise<boolean> {
|
authorizeSearchingProtectedNotesText(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.SearchProtectedNotesText)
|
return this.authorizeAction(ChallengeReason.SearchProtectedNotesText, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizeFileImport(): Promise<boolean> {
|
authorizeFileImport(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.ImportFile)
|
return this.authorizeAction(ChallengeReason.ImportFile, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorizeBackupCreation(): Promise<boolean> {
|
async authorizeBackupCreation(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.ExportBackup, {
|
return this.authorizeAction(ChallengeReason.ExportBackup, {
|
||||||
fallBackToAccountPassword: true,
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorizeMfaDisable(): Promise<boolean> {
|
async authorizeMfaDisable(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.DisableMfa, {
|
return this.authorizeAction(ChallengeReason.DisableMfa, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
requireAccountPassword: true,
|
requireAccountPassword: true,
|
||||||
|
forcePrompt: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorizeAutolockIntervalChange(): Promise<boolean> {
|
async authorizeAutolockIntervalChange(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.ChangeAutolockInterval)
|
return this.authorizeAction(ChallengeReason.ChangeAutolockInterval, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorizeSessionRevoking(): Promise<boolean> {
|
async authorizeSessionRevoking(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.RevokeSession)
|
return this.authorizeAction(ChallengeReason.RevokeSession, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorizeListedPublishing(): Promise<boolean> {
|
async authorizeListedPublishing(): Promise<boolean> {
|
||||||
return this.authorizeAction(ChallengeReason.AuthorizeNoteForListed, { forcePrompt: true })
|
return this.authorizeAction(ChallengeReason.AuthorizeNoteForListed, {
|
||||||
|
fallBackToAccountPassword: true,
|
||||||
|
requireAccountPassword: false,
|
||||||
|
forcePrompt: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorizeAction(
|
async authorizeAction(
|
||||||
reason: ChallengeReason,
|
reason: ChallengeReason,
|
||||||
{ fallBackToAccountPassword = true, requireAccountPassword = false, forcePrompt = false } = {},
|
dto: { fallBackToAccountPassword: boolean; requireAccountPassword: boolean; forcePrompt: boolean },
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return this.validateOrRenewSession(reason, {
|
return this.validateOrRenewSession(reason, dto)
|
||||||
requireAccountPassword,
|
|
||||||
fallBackToAccountPassword,
|
|
||||||
forcePrompt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getMobilePasscodeTimingOptions(): TimingDisplayOption[] {
|
getMobilePasscodeTimingOptions(): TimingDisplayOption[] {
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
export * from './ClientInterface'
|
|
||||||
export * from './ProtectionService'
|
export * from './ProtectionService'
|
||||||
export * from './MobileUnlockTiming'
|
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ import {
|
|||||||
ChallengeReason,
|
ChallengeReason,
|
||||||
ChallengePromptTitle,
|
ChallengePromptTitle,
|
||||||
EncryptionService,
|
EncryptionService,
|
||||||
|
SessionsClientInterface,
|
||||||
|
SessionManagerResponse,
|
||||||
|
SessionStrings,
|
||||||
|
SignInStrings,
|
||||||
|
INVALID_PASSWORD_COST,
|
||||||
|
API_MESSAGE_FALLBACK_LOGIN_FAIL,
|
||||||
|
API_MESSAGE_GENERIC_SYNC_FAIL,
|
||||||
|
EXPIRED_PROTOCOL_VERSION,
|
||||||
|
StrictSignInFailed,
|
||||||
|
UNSUPPORTED_KEY_DERIVATION,
|
||||||
|
UNSUPPORTED_PROTOCOL_VERSION,
|
||||||
|
Challenge,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { Base64String } from '@standardnotes/sncrypto-common'
|
import { Base64String } from '@standardnotes/sncrypto-common'
|
||||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||||
@@ -17,11 +29,9 @@ import { CopyPayloadWithContentOverride } from '@standardnotes/models'
|
|||||||
import { isNullOrUndefined } from '@standardnotes/utils'
|
import { isNullOrUndefined } from '@standardnotes/utils'
|
||||||
import { JwtSession } from './Sessions/JwtSession'
|
import { JwtSession } from './Sessions/JwtSession'
|
||||||
import { KeyParamsFromApiResponse, SNRootKeyParams, SNRootKey, CreateNewRootKey } from '@standardnotes/encryption'
|
import { KeyParamsFromApiResponse, SNRootKeyParams, SNRootKey, CreateNewRootKey } from '@standardnotes/encryption'
|
||||||
import { SessionStrings, SignInStrings } from '../Api/Messages'
|
|
||||||
import { RemoteSession, RawStorageValue } from './Sessions/Types'
|
import { RemoteSession, RawStorageValue } from './Sessions/Types'
|
||||||
import { Session } from './Sessions/Session'
|
import { Session } from './Sessions/Session'
|
||||||
import { SessionFromRawStorageValue } from './Sessions/Generator'
|
import { SessionFromRawStorageValue } from './Sessions/Generator'
|
||||||
import { SessionsClientInterface } from './SessionsClientInterface'
|
|
||||||
import { ShareToken } from './ShareToken'
|
import { ShareToken } from './ShareToken'
|
||||||
import { SNApiService } from '../Api/ApiService'
|
import { SNApiService } from '../Api/ApiService'
|
||||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||||
@@ -31,9 +41,8 @@ import { Subscription } from '@standardnotes/security'
|
|||||||
import { TokenSession } from './Sessions/TokenSession'
|
import { TokenSession } from './Sessions/TokenSession'
|
||||||
import { UuidString } from '@Lib/Types/UuidString'
|
import { UuidString } from '@Lib/Types/UuidString'
|
||||||
import * as Common from '@standardnotes/common'
|
import * as Common from '@standardnotes/common'
|
||||||
import * as Messages from '../Api/Messages'
|
|
||||||
import * as Responses from '@standardnotes/responses'
|
import * as Responses from '@standardnotes/responses'
|
||||||
import { Challenge, ChallengeService } from '../Challenge'
|
import { ChallengeService } from '../Challenge'
|
||||||
import {
|
import {
|
||||||
ApiCallError,
|
ApiCallError,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
@@ -46,12 +55,6 @@ import {
|
|||||||
export const MINIMUM_PASSWORD_LENGTH = 8
|
export const MINIMUM_PASSWORD_LENGTH = 8
|
||||||
export const MissingAccountParams = 'missing-params'
|
export const MissingAccountParams = 'missing-params'
|
||||||
|
|
||||||
type SessionManagerResponse = {
|
|
||||||
response: Responses.HttpResponse
|
|
||||||
rootKey?: SNRootKey
|
|
||||||
keyParams?: Common.AnyKeyParamsContent
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleanedEmailString = (email: string) => {
|
const cleanedEmailString = (email: string) => {
|
||||||
return email.trim().toLowerCase()
|
return email.trim().toLowerCase()
|
||||||
}
|
}
|
||||||
@@ -338,7 +341,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
|||||||
const keyParams = KeyParamsFromApiResponse(response as Responses.KeyParamsResponse, email)
|
const keyParams = KeyParamsFromApiResponse(response as Responses.KeyParamsResponse, email)
|
||||||
if (!keyParams || !keyParams.version) {
|
if (!keyParams || !keyParams.version) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(Messages.API_MESSAGE_FALLBACK_LOGIN_FAIL),
|
response: this.apiService.createErrorResponse(API_MESSAGE_FALLBACK_LOGIN_FAIL),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { keyParams, response, mfaKeyPath, mfaCode }
|
return { keyParams, response, mfaKeyPath, mfaCode }
|
||||||
@@ -388,11 +391,11 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
|||||||
if (!this.protocolService.supportedVersions().includes(keyParams.version)) {
|
if (!this.protocolService.supportedVersions().includes(keyParams.version)) {
|
||||||
if (this.protocolService.isVersionNewerThanLibraryVersion(keyParams.version)) {
|
if (this.protocolService.isVersionNewerThanLibraryVersion(keyParams.version)) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(Messages.UNSUPPORTED_PROTOCOL_VERSION),
|
response: this.apiService.createErrorResponse(UNSUPPORTED_PROTOCOL_VERSION),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(Messages.EXPIRED_PROTOCOL_VERSION),
|
response: this.apiService.createErrorResponse(EXPIRED_PROTOCOL_VERSION),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -402,7 +405,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
|||||||
const minimum = this.protocolService.costMinimumForVersion(keyParams.version)
|
const minimum = this.protocolService.costMinimumForVersion(keyParams.version)
|
||||||
if (keyParams.content002.pw_cost < minimum) {
|
if (keyParams.content002.pw_cost < minimum) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(Messages.INVALID_PASSWORD_COST),
|
response: this.apiService.createErrorResponse(INVALID_PASSWORD_COST),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,14 +418,14 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
|||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(Messages.API_MESSAGE_FALLBACK_LOGIN_FAIL),
|
response: this.apiService.createErrorResponse(API_MESSAGE_FALLBACK_LOGIN_FAIL),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.protocolService.platformSupportsKeyDerivation(keyParams)) {
|
if (!this.protocolService.platformSupportsKeyDerivation(keyParams)) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(Messages.UNSUPPORTED_KEY_DERIVATION),
|
response: this.apiService.createErrorResponse(UNSUPPORTED_KEY_DERIVATION),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,9 +436,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
|||||||
if (!isNullOrUndefined(minAllowedVersion)) {
|
if (!isNullOrUndefined(minAllowedVersion)) {
|
||||||
if (!Common.leftVersionGreaterThanOrEqualToRight(keyParams.version, minAllowedVersion)) {
|
if (!Common.leftVersionGreaterThanOrEqualToRight(keyParams.version, minAllowedVersion)) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(
|
response: this.apiService.createErrorResponse(StrictSignInFailed(keyParams.version, minAllowedVersion)),
|
||||||
Messages.StrictSignInFailed(keyParams.version, minAllowedVersion),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,7 +533,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
|||||||
public async revokeAllOtherSessions(): Promise<void> {
|
public async revokeAllOtherSessions(): Promise<void> {
|
||||||
const response = await this.getSessionsList()
|
const response = await this.getSessionsList()
|
||||||
if (response.error != undefined || response.data == undefined) {
|
if (response.error != undefined || response.data == undefined) {
|
||||||
throw new Error(response.error?.message ?? Messages.API_MESSAGE_GENERIC_SYNC_FAIL)
|
throw new Error(response.error?.message ?? API_MESSAGE_GENERIC_SYNC_FAIL)
|
||||||
}
|
}
|
||||||
const sessions = response.data as RemoteSession[]
|
const sessions = response.data as RemoteSession[]
|
||||||
const otherSessions = sessions.filter((session) => !session.current)
|
const otherSessions = sessions.filter((session) => !session.current)
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import { ClientDisplayableError, User } from '@standardnotes/responses'
|
|
||||||
import { Base64String } from '@standardnotes/sncrypto-common'
|
|
||||||
|
|
||||||
export interface SessionsClientInterface {
|
|
||||||
createDemoShareToken(): Promise<Base64String | ClientDisplayableError>
|
|
||||||
populateSessionFromDemoShareToken(token: Base64String): Promise<void>
|
|
||||||
getUser(): User | undefined
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './SessionManager'
|
export * from './SessionManager'
|
||||||
export * from './Sessions'
|
export * from './Sessions'
|
||||||
export * from './SessionsClientInterface'
|
|
||||||
export * from './ShareToken'
|
export * from './ShareToken'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SettingsList } from './SettingsList'
|
import { SettingsList } from './SettingsList'
|
||||||
import { SettingName, SensitiveSettingName, SubscriptionSettingName } from '@standardnotes/settings'
|
import { SettingName, SensitiveSettingName, SubscriptionSettingName } from '@standardnotes/settings'
|
||||||
import * as messages from '../Api/Messages'
|
import { API_MESSAGE_INVALID_SESSION } from '@standardnotes/services'
|
||||||
import { StatusCode, User } from '@standardnotes/responses'
|
import { StatusCode, User } from '@standardnotes/responses'
|
||||||
import { SettingsServerInterface } from './SettingsServerInterface'
|
import { SettingsServerInterface } from './SettingsServerInterface'
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export class SettingsGateway {
|
|||||||
private get userUuid() {
|
private get userUuid() {
|
||||||
const user = this.getUser()
|
const user = this.getUser()
|
||||||
if (user == undefined || user.uuid == undefined) {
|
if (user == undefined || user.uuid == undefined) {
|
||||||
throw new Error(messages.API_MESSAGE_INVALID_SESSION)
|
throw new Error(API_MESSAGE_INVALID_SESSION)
|
||||||
}
|
}
|
||||||
return user.uuid
|
return user.uuid
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import { HttpResponse, MinimalHttpResponse } from '@standardnotes/responses'
|
|
||||||
|
|
||||||
export interface UserServerInterface {
|
|
||||||
deleteAccount(userUuid: string): Promise<HttpResponse | MinimalHttpResponse>
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from './UserServerInterface'
|
|
||||||
export * from './UserService'
|
|
||||||
@@ -19,4 +19,3 @@ export * from './Settings'
|
|||||||
export * from './Singleton/SingletonManager'
|
export * from './Singleton/SingletonManager'
|
||||||
export * from './Storage/DiskStorageService'
|
export * from './Storage/DiskStorageService'
|
||||||
export * from './Sync'
|
export * from './Sync'
|
||||||
export * from './User'
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { ConfirmStrings } from './Confirm'
|
import { ConfirmStrings } from './Confirm'
|
||||||
import { InfoStrings } from './Info'
|
|
||||||
import { InputStrings } from './Input'
|
import { InputStrings } from './Input'
|
||||||
import { NetworkStrings } from './Network'
|
import { NetworkStrings } from './Network'
|
||||||
|
|
||||||
export const Strings = {
|
export const Strings = {
|
||||||
Info: InfoStrings,
|
|
||||||
Network: NetworkStrings,
|
Network: NetworkStrings,
|
||||||
Confirm: ConfirmStrings,
|
Confirm: ConfirmStrings,
|
||||||
Input: InputStrings,
|
Input: InputStrings,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/api": "workspace:*",
|
"@standardnotes/api": "workspace:*",
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/domain-events": "^2.39.0",
|
"@standardnotes/domain-events": "^2.39.0",
|
||||||
"@standardnotes/encryption": "workspace:*",
|
"@standardnotes/encryption": "workspace:*",
|
||||||
"@standardnotes/features": "workspace:*",
|
"@standardnotes/features": "workspace:*",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"test": "jest spec"
|
"test": "jest spec"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"@standardnotes/features": "workspace:^",
|
"@standardnotes/features": "workspace:^",
|
||||||
"@standardnotes/filepicker": "workspace:^",
|
"@standardnotes/filepicker": "workspace:^",
|
||||||
"@standardnotes/services": "workspace:^",
|
"@standardnotes/services": "workspace:^",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"test": "jest spec"
|
"test": "jest spec"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.39.0",
|
"@standardnotes/common": "^1.43.0",
|
||||||
"dompurify": "^2.3.8",
|
"dompurify": "^2.3.8",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"reflect-metadata": "^0.1.13"
|
"reflect-metadata": "^0.1.13"
|
||||||
|
|||||||
36
yarn.lock
36
yarn.lock
@@ -6354,7 +6354,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/api@workspace:packages/api"
|
resolution: "@standardnotes/api@workspace:packages/api"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/encryption": "workspace:*"
|
"@standardnotes/encryption": "workspace:*"
|
||||||
"@standardnotes/models": "workspace:*"
|
"@standardnotes/models": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
@@ -6521,7 +6521,7 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@standardnotes/common@npm:1.40.0, @standardnotes/common@npm:^1.23.1, @standardnotes/common@npm:^1.39.0":
|
"@standardnotes/common@npm:1.40.0, @standardnotes/common@npm:^1.23.1":
|
||||||
version: 1.40.0
|
version: 1.40.0
|
||||||
resolution: "@standardnotes/common@npm:1.40.0"
|
resolution: "@standardnotes/common@npm:1.40.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6530,6 +6530,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@standardnotes/common@npm:^1.43.0":
|
||||||
|
version: 1.43.0
|
||||||
|
resolution: "@standardnotes/common@npm:1.43.0"
|
||||||
|
dependencies:
|
||||||
|
reflect-metadata: ^0.1.13
|
||||||
|
checksum: 59300594418a5cb9d4b811240c23007bb927df6f620cb37460a978d82b1b8baf7107e4a3557110c032636ab02f7e61669613d35bdcac2bcb0e8f0e66b8a16f8d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@standardnotes/component-relay@npm:2.2.0":
|
"@standardnotes/component-relay@npm:2.2.0":
|
||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
resolution: "@standardnotes/component-relay@npm:2.2.0"
|
resolution: "@standardnotes/component-relay@npm:2.2.0"
|
||||||
@@ -6713,7 +6722,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/encryption@workspace:packages/encryption"
|
resolution: "@standardnotes/encryption@workspace:packages/encryption"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/config": 2.4.3
|
"@standardnotes/config": 2.4.3
|
||||||
"@standardnotes/models": "workspace:*"
|
"@standardnotes/models": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
@@ -6755,7 +6764,7 @@ __metadata:
|
|||||||
resolution: "@standardnotes/features@workspace:packages/features"
|
resolution: "@standardnotes/features@workspace:packages/features"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/auth": ^3.19.4
|
"@standardnotes/auth": ^3.19.4
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/security": ^1.2.0
|
"@standardnotes/security": ^1.2.0
|
||||||
"@types/jest": ^28.1.5
|
"@types/jest": ^28.1.5
|
||||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||||
@@ -6771,7 +6780,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/filepicker@workspace:packages/filepicker"
|
resolution: "@standardnotes/filepicker@workspace:packages/filepicker"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/files": "workspace:*"
|
"@standardnotes/files": "workspace:*"
|
||||||
"@standardnotes/utils": "workspace:*"
|
"@standardnotes/utils": "workspace:*"
|
||||||
"@types/jest": ^28.1.5
|
"@types/jest": ^28.1.5
|
||||||
@@ -6790,7 +6799,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/files@workspace:packages/files"
|
resolution: "@standardnotes/files@workspace:packages/files"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/encryption": "workspace:*"
|
"@standardnotes/encryption": "workspace:*"
|
||||||
"@standardnotes/models": "workspace:*"
|
"@standardnotes/models": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
@@ -7119,7 +7128,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/models@workspace:packages/models"
|
resolution: "@standardnotes/models@workspace:packages/models"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/features": "workspace:*"
|
"@standardnotes/features": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
"@standardnotes/utils": "workspace:*"
|
"@standardnotes/utils": "workspace:*"
|
||||||
@@ -7170,7 +7179,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/responses@workspace:packages/responses"
|
resolution: "@standardnotes/responses@workspace:packages/responses"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/features": "workspace:*"
|
"@standardnotes/features": "workspace:*"
|
||||||
"@standardnotes/security": ^1.1.0
|
"@standardnotes/security": ^1.1.0
|
||||||
"@types/jest": ^28.1.5
|
"@types/jest": ^28.1.5
|
||||||
@@ -7228,12 +7237,13 @@ __metadata:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/api": "workspace:^"
|
"@standardnotes/api": "workspace:^"
|
||||||
"@standardnotes/auth": ^3.19.4
|
"@standardnotes/auth": ^3.19.4
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/encryption": "workspace:^"
|
"@standardnotes/encryption": "workspace:^"
|
||||||
"@standardnotes/files": "workspace:^"
|
"@standardnotes/files": "workspace:^"
|
||||||
"@standardnotes/models": "workspace:^"
|
"@standardnotes/models": "workspace:^"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
"@standardnotes/security": ^1.2.0
|
"@standardnotes/security": ^1.2.0
|
||||||
|
"@standardnotes/sncrypto-common": "workspace:^"
|
||||||
"@standardnotes/utils": "workspace:*"
|
"@standardnotes/utils": "workspace:*"
|
||||||
"@types/jest": ^28.1.5
|
"@types/jest": ^28.1.5
|
||||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||||
@@ -7293,7 +7303,7 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@standardnotes/sncrypto-common@workspace:*, @standardnotes/sncrypto-common@workspace:packages/sncrypto-common":
|
"@standardnotes/sncrypto-common@workspace:*, @standardnotes/sncrypto-common@workspace:^, @standardnotes/sncrypto-common@workspace:packages/sncrypto-common":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/sncrypto-common@workspace:packages/sncrypto-common"
|
resolution: "@standardnotes/sncrypto-common@workspace:packages/sncrypto-common"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -7343,7 +7353,7 @@ __metadata:
|
|||||||
"@babel/core": "*"
|
"@babel/core": "*"
|
||||||
"@babel/preset-env": "*"
|
"@babel/preset-env": "*"
|
||||||
"@standardnotes/api": "workspace:*"
|
"@standardnotes/api": "workspace:*"
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/domain-events": ^2.39.0
|
"@standardnotes/domain-events": ^2.39.0
|
||||||
"@standardnotes/encryption": "workspace:*"
|
"@standardnotes/encryption": "workspace:*"
|
||||||
"@standardnotes/features": "workspace:*"
|
"@standardnotes/features": "workspace:*"
|
||||||
@@ -7478,7 +7488,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/ui-services@workspace:packages/ui-services"
|
resolution: "@standardnotes/ui-services@workspace:packages/ui-services"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@standardnotes/features": "workspace:^"
|
"@standardnotes/features": "workspace:^"
|
||||||
"@standardnotes/filepicker": "workspace:^"
|
"@standardnotes/filepicker": "workspace:^"
|
||||||
"@standardnotes/services": "workspace:^"
|
"@standardnotes/services": "workspace:^"
|
||||||
@@ -7499,7 +7509,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@standardnotes/utils@workspace:packages/utils"
|
resolution: "@standardnotes/utils@workspace:packages/utils"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.39.0
|
"@standardnotes/common": ^1.43.0
|
||||||
"@types/dompurify": ^2.3.3
|
"@types/dompurify": ^2.3.3
|
||||||
"@types/jest": ^28.1.5
|
"@types/jest": ^28.1.5
|
||||||
"@types/jsdom": ^16.2.14
|
"@types/jsdom": ^16.2.14
|
||||||
|
|||||||
Reference in New Issue
Block a user