Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleaner madness #566

Merged
merged 10 commits into from
Oct 2, 2023
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# edge-core-js

## Unreleased

- added: Export cleaners for server types and testing data types.
- deprecated: `EdgeContext.listRecoveryQuestionChoices`. The GUI provides its own localized strings now.

## v1.7.0 (2023-09-12)

- added: Add a `ChallengeError` and related types, which will allow the login server to request CAPTCHA validation.
Expand Down
9 changes: 5 additions & 4 deletions src/core/context/context-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,6 @@ export function makeContextApi(ai: ApiInput): EdgeContext {
return await getQuestions2(ai, base58.parse(recovery2Key), username)
},

async listRecoveryQuestionChoices(): Promise<EdgeRecoveryQuestionChoice[]> {
return await listRecoveryQuestionChoices(ai)
},

async requestEdgeLogin(
opts?: EdgeAccountOptions
): Promise<EdgePendingEdgeLogin> {
Expand Down Expand Up @@ -271,6 +267,11 @@ export function makeContextApi(ai: ApiInput): EdgeContext {
async changeLogSettings(settings: Partial<EdgeLogSettings>): Promise<void> {
const newSettings = { ...ai.props.state.logSettings, ...settings }
ai.props.dispatch({ type: 'CHANGE_LOG_SETTINGS', payload: newSettings })
},

/** @deprecated The GUI provides its own localized strings now. */
async listRecoveryQuestionChoices(): Promise<EdgeRecoveryQuestionChoice[]> {
return await listRecoveryQuestionChoices(ai)
}
}
bridgifyObject(out)
Expand Down
40 changes: 14 additions & 26 deletions src/core/fake/fake-db.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { FakeUser, LoginDump } from '../../types/fake-types'
import { EdgeLoginDump, EdgeRepoDump } from '../../types/fake-types'
import {
EdgeBox,
EdgeLobbyReply,
EdgeLobbyRequest,
LoginPayload
Expand All @@ -20,22 +19,15 @@ export interface DbLobby {
/**
* A login object stored in the fake database.
*/
export type DbLogin = Omit<LoginDump, 'children'>

/**
* A sync repo stored in the fake database.
*/
export interface DbRepo {
[path: string]: EdgeBox
}
export type DbLogin = Omit<EdgeLoginDump, 'children'>

/**
* Emulates the Airbitz login server database.
*/
export class FakeDb {
lobbies: { [lobbyId: string]: DbLobby }
logins: DbLogin[]
repos: { [syncKey: string]: DbRepo }
repos: { [syncKey: string]: EdgeRepoDump }

constructor() {
this.lobbies = {}
Expand Down Expand Up @@ -78,25 +70,21 @@ export class FakeDb {

// Dumping & restoration --------------------------------------------

setupFakeUser(user: FakeUser): void {
const setupLogin = (dump: LoginDump): void => {
const { children, ...rest } = dump
this.insertLogin(rest)
for (const child of children) {
child.parentId = dump.loginId
setupLogin(child)
}
setupLogin(dump: EdgeLoginDump): void {
const { children, ...rest } = dump
this.insertLogin(rest)
for (const child of children) {
child.parentId = dump.loginId
this.setupLogin(child)
}
setupLogin(user.server)
}

// Create fake repos:
for (const syncKey of Object.keys(user.repos)) {
this.repos[syncKey] = { ...user.repos[syncKey] }
}
setupRepo(syncKey: string, repo: EdgeRepoDump): void {
this.repos[syncKey] = repo
}

dumpLogin(login: DbLogin): LoginDump {
const makeTree = (login: DbLogin): LoginDump => ({
dumpLogin(login: DbLogin): EdgeLoginDump {
const makeTree = (login: DbLogin): EdgeLoginDump => ({
...login,
children: this.getLoginsByParent(login).map(login => makeTree(login))
})
Expand Down
57 changes: 40 additions & 17 deletions src/core/fake/fake-responses.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { uncleaner } from 'cleaners'
import { Cleaner } from 'cleaners'
import { HttpHeaders, HttpResponse } from 'serverlet'

import { VoucherDump } from '../../types/fake-types'
import { EdgeVoucherDump } from '../../types/fake-types'
import {
asOtpErrorPayload,
asPasswordErrorPayload
wasLoginResponseBody,
wasOtpErrorPayload,
wasPasswordErrorPayload
} from '../../types/server-cleaners'
import { DbLogin } from './fake-db'

const wasOtpErrorPayload = uncleaner(asOtpErrorPayload)
const wasPasswordErrorPayload = uncleaner(asPasswordErrorPayload)

interface LoginStatusCode {
code: number
httpStatus: number
Expand Down Expand Up @@ -104,19 +102,37 @@ export const statusCodes = {
}
}

export function cleanRequest<T>(
cleaner: Cleaner<T>,
raw: unknown
): [T | undefined, HttpResponse] {
try {
const clean = cleaner(raw)
return [clean, { status: 200 }]
} catch (error) {
return [
undefined,
statusResponse(
statusCodes.invalidRequest,
`Invalid request: ${String(error)}`
)
]
}
}

/**
* Construct an HttpResponse object with a JSON body.
*/
export function jsonResponse(
body: unknown,
opts: { status?: number; headers?: HttpHeaders } = {}
): Promise<HttpResponse> {
): HttpResponse {
const { status = 200, headers = {} } = opts
return Promise.resolve({
return {
status,
headers: { 'content-type': 'application/json', ...headers },
body: JSON.stringify(body)
})
}
}

/**
Expand All @@ -125,9 +141,12 @@ export function jsonResponse(
export function statusResponse(
statusCode: LoginStatusCode = statusCodes.success,
message: string = statusCode.message
): Promise<HttpResponse> {
): HttpResponse {
const { code, httpStatus } = statusCode
const body = { status_code: code, message }
const body = wasLoginResponseBody({
status_code: code,
message
})
return jsonResponse(body, { status: httpStatus })
}

Expand All @@ -138,9 +157,13 @@ export function payloadResponse(
payload: unknown,
statusCode: LoginStatusCode = statusCodes.success,
message: string = statusCode.message
): Promise<HttpResponse> {
): HttpResponse {
const { code, httpStatus } = statusCode
const body = { status_code: code, message, results: payload }
const body = wasLoginResponseBody({
status_code: code,
message,
results: payload
})
return jsonResponse(body, { status: httpStatus })
}

Expand All @@ -151,9 +174,9 @@ export function otpErrorResponse(
login: DbLogin,
opts: {
reason?: 'ip' | 'otp'
voucher?: VoucherDump
voucher?: EdgeVoucherDump
} = {}
): Promise<HttpResponse> {
): HttpResponse {
const { reason = 'otp', voucher } = opts
return payloadResponse(
wasOtpErrorPayload({
Expand All @@ -172,7 +195,7 @@ export function otpErrorResponse(
/**
* A password failure, with timeout.
*/
export function passwordErrorResponse(wait: number): Promise<HttpResponse> {
export function passwordErrorResponse(wait: number): HttpResponse {
return payloadResponse(
wasPasswordErrorPayload({
wait_seconds: wait
Expand Down
Loading