chore: remove calling payments server for subscriptions if using third party api hosts (#2398)
This commit is contained in:
@@ -9,13 +9,13 @@ import { AnyFeatureDescription } from '@standardnotes/features'
|
||||
export interface LegacyApiServiceInterface
|
||||
extends AbstractService<ApiServiceEvent, ApiServiceEventData>,
|
||||
FilesApiInterface {
|
||||
isThirdPartyHostUsed(): boolean
|
||||
setHost(host: string): Promise<void>
|
||||
getHost(): string
|
||||
|
||||
downloadOfflineFeaturesFromRepo(
|
||||
repo: SNFeatureRepo,
|
||||
): Promise<{ features: AnyFeatureDescription[]; roles: string[] } | ClientDisplayableError>
|
||||
downloadOfflineFeaturesFromRepo(dto: {
|
||||
repo: SNFeatureRepo
|
||||
trustedFeatureHosts: string[]
|
||||
}): Promise<{ features: AnyFeatureDescription[]; roles: string[] } | ClientDisplayableError>
|
||||
|
||||
downloadFeatureUrl(url: string): Promise<HttpResponse>
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ export interface ApplicationInterface {
|
||||
|
||||
hasAccount(): boolean
|
||||
setCustomHost(host: string): Promise<void>
|
||||
isThirdPartyHostUsed(): boolean
|
||||
isUsingHomeServer(): Promise<boolean>
|
||||
|
||||
importData(data: BackupFile, awaitSync?: boolean): Promise<ImportDataReturnType>
|
||||
|
||||
@@ -7,14 +7,17 @@ import { SubscriptionApiServiceInterface } from '@standardnotes/api'
|
||||
import { Invitation } from '@standardnotes/models'
|
||||
import { InternalEventBusInterface } from '..'
|
||||
import { SubscriptionManager } from './SubscriptionManager'
|
||||
import { IsApplicationUsingThirdPartyHost } from '../UseCase/IsApplicationUsingThirdPartyHost'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
describe('SubscriptionManager', () => {
|
||||
let subscriptionApiService: SubscriptionApiServiceInterface
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
let sessions: SessionsClientInterface
|
||||
let storage: StorageServiceInterface
|
||||
let isApplicationUsingThirdPartyHostUseCase: IsApplicationUsingThirdPartyHost
|
||||
|
||||
const createManager = () => new SubscriptionManager(subscriptionApiService, sessions, storage, internalEventBus)
|
||||
const createManager = () => new SubscriptionManager(subscriptionApiService, sessions, storage, isApplicationUsingThirdPartyHostUseCase, internalEventBus)
|
||||
|
||||
beforeEach(() => {
|
||||
subscriptionApiService = {} as jest.Mocked<SubscriptionApiServiceInterface>
|
||||
@@ -31,6 +34,9 @@ describe('SubscriptionManager', () => {
|
||||
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
|
||||
internalEventBus.addEventHandler = jest.fn()
|
||||
internalEventBus.publish = jest.fn()
|
||||
|
||||
isApplicationUsingThirdPartyHostUseCase = {} as jest.Mocked<IsApplicationUsingThirdPartyHost>
|
||||
isApplicationUsingThirdPartyHostUseCase.execute = jest.fn().mockReturnValue(Result.ok(false))
|
||||
})
|
||||
|
||||
describe('event handling', () => {
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
} from '@standardnotes/responses'
|
||||
import { SubscriptionManagerEvent } from './SubscriptionManagerEvent'
|
||||
import { ApplicationStageChangedEventPayload } from '../Event/ApplicationStageChangedEventPayload'
|
||||
import { IsApplicationUsingThirdPartyHost } from '../UseCase/IsApplicationUsingThirdPartyHost'
|
||||
|
||||
export class SubscriptionManager
|
||||
extends AbstractService<SubscriptionManagerEvent>
|
||||
@@ -34,6 +35,7 @@ export class SubscriptionManager
|
||||
private subscriptionApiService: SubscriptionApiServiceInterface,
|
||||
private sessions: SessionsClientInterface,
|
||||
private storage: StorageServiceInterface,
|
||||
private isApplicationUsingThirdPartyHostUseCase: IsApplicationUsingThirdPartyHost,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -43,7 +45,15 @@ export class SubscriptionManager
|
||||
switch (event.type) {
|
||||
case ApplicationEvent.Launched: {
|
||||
void this.fetchOnlineSubscription()
|
||||
void this.fetchAvailableSubscriptions()
|
||||
|
||||
const isThirdPartyHostUsedOrError = this.isApplicationUsingThirdPartyHostUseCase.execute()
|
||||
if (isThirdPartyHostUsedOrError.isFailed()) {
|
||||
break
|
||||
}
|
||||
const isThirdPartyHostUsed = isThirdPartyHostUsedOrError.getValue()
|
||||
if (!isThirdPartyHostUsed) {
|
||||
void this.fetchAvailableSubscriptions()
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { GetHost } from '../..'
|
||||
import { IsApplicationUsingThirdPartyHost } from './IsApplicationUsingThirdPartyHost'
|
||||
|
||||
describe('IsApplicationUsingThirdPartyHost', () => {
|
||||
let getHostUseCase: GetHost
|
||||
|
||||
const createUseCase = () => new IsApplicationUsingThirdPartyHost(getHostUseCase)
|
||||
|
||||
beforeEach(() => {
|
||||
getHostUseCase = {} as jest.Mocked<GetHost>
|
||||
getHostUseCase.execute = jest.fn().mockReturnValue(Result.ok('https://api.standardnotes.com'))
|
||||
})
|
||||
|
||||
it('returns true if host is localhost', () => {
|
||||
getHostUseCase.execute = jest.fn().mockReturnValue(Result.ok('http://localhost:3000'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
const result = useCase.execute()
|
||||
|
||||
expect(result.getValue()).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false if host is api.standardnotes.com', () => {
|
||||
getHostUseCase.execute = jest.fn().mockReturnValue(Result.ok('https://api.standardnotes.com'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
const result = useCase.execute()
|
||||
|
||||
expect(result.getValue()).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false if host is sync.standardnotes.org', () => {
|
||||
getHostUseCase.execute = jest.fn().mockReturnValue(Result.ok('https://sync.standardnotes.org'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
const result = useCase.execute()
|
||||
|
||||
expect(result.getValue()).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false if host is files.standardnotes.com', () => {
|
||||
getHostUseCase.execute = jest.fn().mockReturnValue(Result.ok('https://files.standardnotes.com'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
const result = useCase.execute()
|
||||
|
||||
expect(result.getValue()).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true if host is not first party', () => {
|
||||
getHostUseCase.execute = jest.fn().mockReturnValue(Result.ok('https://example.com'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
const result = useCase.execute()
|
||||
|
||||
expect(result.getValue()).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
import { GetHost } from './GetHost'
|
||||
|
||||
export class IsApplicationUsingThirdPartyHost implements SyncUseCaseInterface<boolean> {
|
||||
private readonly APPLICATION_DEFAULT_HOSTS = ['api.standardnotes.com', 'sync.standardnotes.org']
|
||||
|
||||
private readonly FILES_DEFAULT_HOSTS = ['files.standardnotes.com']
|
||||
|
||||
constructor(private getHostUseCase: GetHost) {}
|
||||
|
||||
execute(): Result<boolean> {
|
||||
const result = this.getHostUseCase.execute()
|
||||
if (result.isFailed()) {
|
||||
return Result.fail(result.getError())
|
||||
}
|
||||
|
||||
const host = result.getValue()
|
||||
|
||||
return Result.ok(!this.isUrlFirstParty(host))
|
||||
}
|
||||
|
||||
private isUrlFirstParty(url: string): boolean {
|
||||
try {
|
||||
const { host } = new URL(url)
|
||||
return this.APPLICATION_DEFAULT_HOSTS.includes(host) || this.FILES_DEFAULT_HOSTS.includes(host)
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,6 +180,7 @@ export * from './UseCase/ChangeAndSaveItem'
|
||||
export * from './UseCase/DiscardItemsLocally'
|
||||
export * from './UseCase/GenerateUuid'
|
||||
export * from './UseCase/GetHost'
|
||||
export * from './UseCase/IsApplicationUsingThirdPartyHost'
|
||||
export * from './UseCase/SetHost'
|
||||
export * from './User/AccountEvent'
|
||||
export * from './User/AccountEventData'
|
||||
|
||||
Reference in New Issue
Block a user