refactor: key rotation (#2383)
This commit is contained in:
@@ -4,8 +4,8 @@ import { WebSocketsService } from './../Services/Api/WebsocketsService'
|
||||
import { MigrationService } from './../Services/Migration/MigrationService'
|
||||
import { LegacyApiService } from './../Services/Api/ApiService'
|
||||
import { FeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { SNPreferencesService } from './../Services/Preferences/PreferencesService'
|
||||
import { SNProtectionService } from './../Services/Protection/ProtectionService'
|
||||
import { PreferencesService } from './../Services/Preferences/PreferencesService'
|
||||
import { ProtectionService } from './../Services/Protection/ProtectionService'
|
||||
import { SessionManager } from './../Services/Session/SessionManager'
|
||||
import { HttpService, HttpServiceInterface, UserRegistrationResponseBody } from '@standardnotes/api'
|
||||
import { ApplicationIdentifier, compareVersions, ProtocolVersion, KeyParamsOrigination } from '@standardnotes/common'
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
FeaturesClientInterface,
|
||||
ItemManagerInterface,
|
||||
SyncServiceInterface,
|
||||
UserClientInterface,
|
||||
UserServiceInterface,
|
||||
MutatorClientInterface,
|
||||
StatusServiceInterface,
|
||||
AlertService,
|
||||
@@ -74,7 +74,6 @@ import {
|
||||
VaultUserServiceInterface,
|
||||
VaultInviteServiceInterface,
|
||||
NotificationServiceEvent,
|
||||
VaultServiceEvent,
|
||||
VaultLockServiceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import {
|
||||
@@ -297,7 +296,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
const uninstall = syncService.addEventObserver(syncEventCallback)
|
||||
this.serviceObservers.push(uninstall)
|
||||
|
||||
const protectionService = this.dependencies.get<SNProtectionService>(TYPES.ProtectionService)
|
||||
const protectionService = this.dependencies.get<ProtectionService>(TYPES.ProtectionService)
|
||||
this.serviceObservers.push(
|
||||
protectionService.addEventObserver((event) => {
|
||||
if (event === ProtectionEvent.UnprotectedSessionBegan) {
|
||||
@@ -329,7 +328,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
}),
|
||||
)
|
||||
|
||||
const preferencesService = this.dependencies.get<SNPreferencesService>(TYPES.PreferencesService)
|
||||
const preferencesService = this.dependencies.get<PreferencesService>(TYPES.PreferencesService)
|
||||
this.serviceObservers.push(
|
||||
preferencesService.addEventObserver(() => {
|
||||
void this.notifyEvent(ApplicationEvent.PreferencesChanged)
|
||||
@@ -1141,7 +1140,6 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
this.dependencies.get(TYPES.SharedVaultService),
|
||||
NotificationServiceEvent.NotificationReceived,
|
||||
)
|
||||
this.events.addEventHandler(this.dependencies.get(TYPES.SharedVaultService), VaultServiceEvent.VaultRootKeyRotated)
|
||||
this.events.addEventHandler(this.dependencies.get(TYPES.SharedVaultService), SyncEvent.ReceivedRemoteSharedVaults)
|
||||
|
||||
this.events.addEventHandler(
|
||||
@@ -1267,8 +1265,8 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
return this.dependencies.get<SyncServiceInterface>(TYPES.SyncService)
|
||||
}
|
||||
|
||||
public get user(): UserClientInterface {
|
||||
return this.dependencies.get<UserClientInterface>(TYPES.UserService)
|
||||
public get user(): UserServiceInterface {
|
||||
return this.dependencies.get<UserServiceInterface>(TYPES.UserService)
|
||||
}
|
||||
|
||||
public get settings(): SettingsService {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -153,6 +153,9 @@ export const TYPES = {
|
||||
IsVaultOwner: Symbol.for('IsVaultOwner'),
|
||||
RemoveItemsFromMemory: Symbol.for('RemoveItemsFromMemory'),
|
||||
ReencryptTypeAItems: Symbol.for('ReencryptTypeAItems'),
|
||||
DecryptErroredPayloads: Symbol.for('DecryptErroredPayloads'),
|
||||
GetKeyPairs: Symbol.for('GetKeyPairs'),
|
||||
ChangeVaultStorageMode: Symbol.for('ChangeVaultStorageMode'),
|
||||
|
||||
// Mappers
|
||||
SessionStorageMapper: Symbol.for('SessionStorageMapper'),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SNPreferencesService } from '../Preferences/PreferencesService'
|
||||
import { PreferencesService } from '../Preferences/PreferencesService'
|
||||
import { GenericItem, Environment, Platform } from '@standardnotes/models'
|
||||
import {
|
||||
InternalEventBusInterface,
|
||||
@@ -68,7 +68,7 @@ describe('featuresService', () => {
|
||||
|
||||
features = {} as jest.Mocked<FeaturesService>
|
||||
|
||||
prefs = {} as jest.Mocked<SNPreferencesService>
|
||||
prefs = {} as jest.Mocked<PreferencesService>
|
||||
prefs.addEventObserver = jest.fn()
|
||||
|
||||
alerts = {} as jest.Mocked<AlertService>
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
StorageServiceInterface,
|
||||
SubscriptionManagerInterface,
|
||||
SyncServiceInterface,
|
||||
UserClientInterface,
|
||||
UserServiceInterface,
|
||||
UserService,
|
||||
} from '@standardnotes/services'
|
||||
import { LegacyApiService, SessionManager } from '../Api'
|
||||
@@ -37,7 +37,7 @@ describe('FeaturesService', () => {
|
||||
let apiService: LegacyApiServiceInterface
|
||||
let webSocketsService: WebSocketsService
|
||||
let settingsService: SettingsClientInterface
|
||||
let userService: UserClientInterface
|
||||
let userService: UserServiceInterface
|
||||
let syncService: SyncServiceInterface
|
||||
let alertService: AlertService
|
||||
let sessionManager: SessionsClientInterface
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
ItemManagerInterface,
|
||||
SyncServiceInterface,
|
||||
SessionsClientInterface,
|
||||
UserClientInterface,
|
||||
UserServiceInterface,
|
||||
SubscriptionManagerInterface,
|
||||
AccountEvent,
|
||||
SubscriptionManagerEvent,
|
||||
@@ -76,7 +76,7 @@ export class FeaturesService
|
||||
private api: LegacyApiServiceInterface,
|
||||
sockets: WebSocketsService,
|
||||
private settings: SettingsClientInterface,
|
||||
private user: UserClientInterface,
|
||||
private user: UserServiceInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
private alerts: AlertService,
|
||||
private sessions: SessionsClientInterface,
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
MutatorClientInterface,
|
||||
SyncServiceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { SNProtectionService } from '../Protection'
|
||||
import { ProtectionService } from '../Protection'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
export class ListedService extends AbstractService implements ListedClientInterface {
|
||||
@@ -23,7 +23,7 @@ export class ListedService extends AbstractService implements ListedClientInterf
|
||||
private itemManager: ItemManager,
|
||||
private settingsService: SettingsService,
|
||||
private httpSerivce: DeprecatedHttpService,
|
||||
private protectionService: SNProtectionService,
|
||||
private protectionService: ProtectionService,
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
|
||||
@@ -56,6 +56,14 @@ describe('mutator service', () => {
|
||||
return mutatorService.insertItem(note)
|
||||
}
|
||||
|
||||
describe('insertItem', () => {
|
||||
it('should throw if attempting to insert already inserted item', async () => {
|
||||
const note = await insertNote('hello')
|
||||
|
||||
expect(mutatorService.insertItem(note)).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('note modifications', () => {
|
||||
it('pinning should not update timestamps', async () => {
|
||||
const note = await insertNote('hello')
|
||||
|
||||
@@ -358,6 +358,11 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
}
|
||||
|
||||
public async insertItem<T extends DecryptedItemInterface>(item: DecryptedItemInterface, setDirty = true): Promise<T> {
|
||||
const existingItem = this.itemManager.findItem<T>(item.uuid)
|
||||
if (existingItem) {
|
||||
throw Error('Attempting to insert item that already exists')
|
||||
}
|
||||
|
||||
if (setDirty) {
|
||||
const mutator = CreateDecryptedMutatorForItem(item, MutationType.UpdateUserTimestamps)
|
||||
const dirtiedPayload = mutator.getResult()
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from '@standardnotes/services'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
export class SNPreferencesService
|
||||
export class PreferencesService
|
||||
extends AbstractService<PreferencesServiceEvent>
|
||||
implements PreferenceServiceInterface, InternalEventHandlerInterface
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ChallengeService } from '../Challenge'
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
import { SNProtectionService } from './ProtectionService'
|
||||
import { ProtectionService } from './ProtectionService'
|
||||
import {
|
||||
InternalEventBus,
|
||||
InternalEventBusInterface,
|
||||
@@ -28,10 +28,10 @@ describe('protectionService', () => {
|
||||
let challengeService: ChallengeService
|
||||
let storageService: DiskStorageService
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
let protectionService: SNProtectionService
|
||||
let protectionService: ProtectionService
|
||||
|
||||
const createService = () => {
|
||||
return new SNProtectionService(encryptionService, mutator, challengeService, storageService, internalEventBus)
|
||||
return new ProtectionService(encryptionService, mutator, challengeService, storageService, internalEventBus)
|
||||
}
|
||||
|
||||
const createFile = (name: string, isProtected?: boolean) => {
|
||||
|
||||
@@ -74,7 +74,7 @@ export const ProtectionSessionDurations = [
|
||||
* like viewing a protected note, as well as managing how long that
|
||||
* authentication should be valid for.
|
||||
*/
|
||||
export class SNProtectionService
|
||||
export class ProtectionService
|
||||
extends AbstractService<ProtectionEvent>
|
||||
implements ProtectionsClientInterface, InternalEventHandlerInterface
|
||||
{
|
||||
|
||||
@@ -32,8 +32,9 @@ import {
|
||||
ApplicationEvent,
|
||||
ApplicationStageChangedEventPayload,
|
||||
ApplicationStage,
|
||||
GetKeyPairs,
|
||||
} from '@standardnotes/services'
|
||||
import { Base64String, PkcKeyPair, PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { Base64String, PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import {
|
||||
SessionBody,
|
||||
ErrorTag,
|
||||
@@ -103,6 +104,7 @@ export class SessionManager
|
||||
private sessionStorageMapper: MapperInterface<Session, Record<string, unknown>>,
|
||||
private legacySessionStorageMapper: MapperInterface<LegacySession, Record<string, unknown>>,
|
||||
private workspaceIdentifier: string,
|
||||
private _getKeyPairs: GetKeyPairs,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -215,11 +217,15 @@ export class SessionManager
|
||||
}
|
||||
|
||||
public getPublicKey(): string {
|
||||
return this.encryptionService.getKeyPair().publicKey
|
||||
const keys = this._getKeyPairs.execute()
|
||||
|
||||
return keys.getValue().encryption.publicKey
|
||||
}
|
||||
|
||||
public getSigningPublicKey(): string {
|
||||
return this.encryptionService.getSigningKeyPair().publicKey
|
||||
const keys = this._getKeyPairs.execute()
|
||||
|
||||
return keys.getValue().signing.publicKey
|
||||
}
|
||||
|
||||
public get userUuid(): string {
|
||||
@@ -625,15 +631,7 @@ export class SessionManager
|
||||
newEmail: parameters.newEmail,
|
||||
})
|
||||
|
||||
let oldKeyPair: PkcKeyPair | undefined
|
||||
let oldSigningKeyPair: PkcKeyPair | undefined
|
||||
|
||||
try {
|
||||
oldKeyPair = this.encryptionService.getKeyPair()
|
||||
oldSigningKeyPair = this.encryptionService.getSigningKeyPair()
|
||||
} catch (error) {
|
||||
void error
|
||||
}
|
||||
const oldKeys = this._getKeyPairs.execute()
|
||||
|
||||
const processedResponse = await this.processChangeCredentialsResponse(
|
||||
rawResponse,
|
||||
@@ -644,13 +642,12 @@ export class SessionManager
|
||||
if (!isErrorResponse(rawResponse)) {
|
||||
if (InternalFeatureService.get().isFeatureEnabled(InternalFeature.Vaults)) {
|
||||
const eventData: UserKeyPairChangedEventData = {
|
||||
previous:
|
||||
oldKeyPair && oldSigningKeyPair
|
||||
? {
|
||||
encryption: oldKeyPair,
|
||||
signing: oldSigningKeyPair,
|
||||
}
|
||||
: undefined,
|
||||
previous: !oldKeys.isFailed()
|
||||
? {
|
||||
encryption: oldKeys.getValue().encryption,
|
||||
signing: oldKeys.getValue().signing,
|
||||
}
|
||||
: undefined,
|
||||
current: {
|
||||
encryption: parameters.newRootKey.encryptionKeyPair,
|
||||
signing: parameters.newRootKey.signingKeyPair,
|
||||
|
||||
Reference in New Issue
Block a user