feat: add services package

This commit is contained in:
Karol Sójko
2022-07-05 20:51:42 +02:00
parent b614c71e79
commit fbfed0a05c
85 changed files with 2418 additions and 28 deletions

View File

@@ -0,0 +1,21 @@
import { ChallengePromptInterface } from './Prompt/ChallengePromptInterface'
import { ChallengeReason } from './Types/ChallengeReason'
import { ChallengeValidation } from './Types/ChallengeValidation'
export interface ChallengeInterface {
readonly id: number
readonly prompts: ChallengePromptInterface[]
readonly reason: ChallengeReason
readonly cancelable: boolean
/** Outside of the modal, this is the title of the modal itself */
get modalTitle(): string
/** Inside of the modal, this is the H1 */
get heading(): string | undefined
/** Inside of the modal, this is the H2 */
get subheading(): string | undefined
hasPromptForValidationType(type: ChallengeValidation): boolean
}

View File

@@ -0,0 +1,13 @@
import { ChallengeInterface } from './ChallengeInterface'
import { ChallengeArtifacts } from './Types/ChallengeArtifacts'
import { ChallengeValidation } from './Types/ChallengeValidation'
import { ChallengeValue } from './Types/ChallengeValue'
export interface ChallengeResponseInterface {
readonly challenge: ChallengeInterface
readonly values: ChallengeValue[]
readonly artifacts?: ChallengeArtifacts
getValueForType(type: ChallengeValidation): ChallengeValue
getDefaultValue(): ChallengeValue
}

View File

@@ -0,0 +1,23 @@
import { AbstractService } from '../Service/AbstractService'
import { ChallengeInterface } from './ChallengeInterface'
import { ChallengePromptInterface } from './Prompt/ChallengePromptInterface'
import { ChallengeResponseInterface } from './ChallengeResponseInterface'
import { ChallengeReason } from './Types/ChallengeReason'
export interface ChallengeServiceInterface extends AbstractService {
/**
* Resolves when the challenge has been completed.
* For non-validated challenges, will resolve when the first value is submitted.
*/
promptForChallengeResponse(challenge: ChallengeInterface): Promise<ChallengeResponseInterface | undefined>
createChallenge(
prompts: ChallengePromptInterface[],
reason: ChallengeReason,
cancelable: boolean,
heading?: string,
subheading?: string,
): ChallengeInterface
completeChallenge(challenge: ChallengeInterface): void
}

View File

@@ -0,0 +1,55 @@
import { assertUnreachable } from '@standardnotes/utils'
import { ChallengeKeyboardType } from '../Types/ChallengeKeyboardType'
import { ChallengeRawValue } from '../Types/ChallengeRawValue'
import { ChallengeValidation } from '../Types/ChallengeValidation'
import { ChallengePromptInterface } from './ChallengePromptInterface'
import { ChallengePromptTitle } from './PromptTitles'
/* istanbul ignore file */
export class ChallengePrompt implements ChallengePromptInterface {
public readonly id = Math.random()
public readonly placeholder: string
public readonly title: string
public readonly validates: boolean
constructor(
public readonly validation: ChallengeValidation,
title?: string,
placeholder?: string,
public readonly secureTextEntry = true,
public readonly keyboardType?: ChallengeKeyboardType,
public readonly initialValue?: ChallengeRawValue,
) {
switch (this.validation) {
case ChallengeValidation.AccountPassword:
this.title = title ?? ChallengePromptTitle.AccountPassword
this.placeholder = placeholder ?? ChallengePromptTitle.AccountPassword
this.validates = true
break
case ChallengeValidation.LocalPasscode:
this.title = title ?? ChallengePromptTitle.LocalPasscode
this.placeholder = placeholder ?? ChallengePromptTitle.LocalPasscode
this.validates = true
break
case ChallengeValidation.Biometric:
this.title = title ?? ChallengePromptTitle.Biometrics
this.placeholder = placeholder ?? ''
this.validates = true
break
case ChallengeValidation.ProtectionSessionDuration:
this.title = title ?? ChallengePromptTitle.RememberFor
this.placeholder = placeholder ?? ''
this.validates = true
break
case ChallengeValidation.None:
this.title = title ?? ''
this.placeholder = placeholder ?? ''
this.validates = false
break
default:
assertUnreachable(this.validation)
}
Object.freeze(this)
}
}

View File

@@ -0,0 +1,19 @@
import { ChallengeKeyboardType } from '../Types/ChallengeKeyboardType'
import { ChallengeRawValue } from '../Types/ChallengeRawValue'
import { ChallengeValidation } from '../Types/ChallengeValidation'
/**
* A Challenge can have many prompts. Each prompt represents a unique input,
* such as a text field, or biometric scanner.
*/
export interface ChallengePromptInterface {
readonly id: number
readonly placeholder: string
readonly title: string
readonly validates: boolean
readonly validation: ChallengeValidation
readonly secureTextEntry: boolean
readonly keyboardType?: ChallengeKeyboardType
readonly initialValue?: ChallengeRawValue
}

View File

@@ -0,0 +1,9 @@
/* istanbul ignore file */
export const ChallengePromptTitle = {
AccountPassword: 'Account Password',
LocalPasscode: 'Application Passcode',
Biometrics: 'Biometrics',
RememberFor: 'Remember For',
Mfa: 'Two-factor Authentication Code',
}

View File

@@ -0,0 +1,8 @@
import { RootKeyInterface } from '@standardnotes/models'
/* istanbul ignore file */
export type ChallengeArtifacts = {
wrappingKey?: RootKeyInterface
rootKey?: RootKeyInterface
}

View File

@@ -0,0 +1,7 @@
/* istanbul ignore file */
/** For mobile */
export enum ChallengeKeyboardType {
Alphanumeric = 'default',
Numeric = 'numeric',
}

View File

@@ -0,0 +1,3 @@
/* istanbul ignore file */
export type ChallengeRawValue = number | string | boolean

View File

@@ -0,0 +1,27 @@
/* istanbul ignore file */
export enum ChallengeReason {
AccessProtectedFile,
AccessProtectedNote,
AddPasscode,
ApplicationUnlock,
ChangeAutolockInterval,
ChangePasscode,
CreateDecryptedBackupWithProtectedItems,
Custom,
DecryptEncryptedFile,
DisableBiometrics,
DisableMfa,
ExportBackup,
ImportFile,
Migration,
ProtocolUpgrade,
RemovePasscode,
ResaveRootKey,
RevokeSession,
SearchProtectedNotesText,
SelectProtectedNote,
UnprotectFile,
UnprotectNote,
DeleteAccount,
}

View File

@@ -0,0 +1,9 @@
/* istanbul ignore file */
export enum ChallengeValidation {
None = 0,
LocalPasscode = 1,
AccountPassword = 2,
Biometric = 3,
ProtectionSessionDuration = 4,
}

View File

@@ -0,0 +1,13 @@
import { ChallengePromptInterface } from '../Prompt/ChallengePromptInterface'
import { ChallengeRawValue } from './ChallengeRawValue'
export interface ChallengeValue {
readonly prompt: ChallengePromptInterface
readonly value: ChallengeRawValue
}
/* istanbul ignore file */
export function CreateChallengeValue(prompt: ChallengePromptInterface, value: ChallengeRawValue): ChallengeValue {
return { prompt, value }
}

View File

@@ -0,0 +1,12 @@
export * from './ChallengeInterface'
export * from './ChallengeResponseInterface'
export * from './ChallengeServiceInterface'
export * from './Prompt/ChallengePrompt'
export * from './Prompt/ChallengePromptInterface'
export * from './Prompt/PromptTitles'
export * from './Types/ChallengeArtifacts'
export * from './Types/ChallengeKeyboardType'
export * from './Types/ChallengeRawValue'
export * from './Types/ChallengeReason'
export * from './Types/ChallengeValidation'
export * from './Types/ChallengeValue'