edge-core-js
Version:
Edge account & wallet management library
204 lines (171 loc) • 5.12 kB
JavaScript
import { makeMemoryDisklet } from 'disklet'
import { base16, base64 } from 'rfc4648'
import { makeFetchFunction } from 'serverlet'
import { bridgifyObject, close } from 'yaob'
import { fixUsername } from '../../client-side'
import {
asEdgeLoginDump,
asEdgeRepoDump,
wasEdgeLoginDump,
wasEdgeRepoDump
} from '../../types/fake-types'
import { asLoginPayload } from '../../types/server-cleaners'
import { base58 } from '../../util/encoding'
import { validateServer } from '../../util/validateServer'
import { applyLoginPayload } from '../login/login'
import { wasLoginStash } from '../login/login-stash'
import { makeContext } from '../root'
import { makeRepoPaths, saveChanges } from '../storage/repo'
import { FakeDb } from './fake-db'
import { makeFakeServer } from './fake-server'
async function saveLogin(io, user) {
const { lastLogin, server } = user
const loginId = base64.parse(user.loginId)
const loginKey = base64.parse(user.loginKey)
const username =
user.username == null ? undefined : fixUsername(user.username)
// Save the stash:
const stash = applyLoginPayload(
{
appId: '',
lastLogin,
loginId,
pendingVouchers: [],
username
},
loginKey,
// The correct cleaner is `asEdgeLoginDump`,
// but the format is close enough that the other cleaner kinda fits:
asLoginPayload(server)
)
const path = `logins/${base58.stringify(loginId)}.json`
await io.disklet
.setText(path, JSON.stringify(wasLoginStash(stash)))
.catch(() => {})
}
async function saveRepo(
io,
syncKey,
repo
) {
const paths = makeRepoPaths(io, {
dataKey: new Uint8Array(0),
syncKey
})
await saveChanges(paths.dataDisklet, repo)
await paths.baseDisklet.setText(
'status.json',
JSON.stringify({ lastSync: 1, lastHash: null })
)
}
/**
* Creates a fake Edge server for unit testing.
*/
export function makeFakeWorld(
ios,
logBackend,
users
) {
const { io, nativeIo } = ios
const fakeDb = new FakeDb()
const fakeServer = makeFakeServer(fakeDb)
// Populate the fake database:
for (const user of users) {
fakeDb.setupLogin(asEdgeLoginDump(user.server))
for (const syncKey of Object.keys(user.repos)) {
fakeDb.setupRepo(syncKey, asEdgeRepoDump(user.repos[syncKey]))
}
}
const contexts = []
const out = {
async close() {
await Promise.all(contexts.map(context => context.close()))
close(out)
},
async makeEdgeContext(opts) {
const {
allowNetworkAccess = false,
cleanDevice = false,
extraFiles = {}
} = opts
const fakeFetch = makeFetchFunction(fakeServer)
const fetch = !allowNetworkAccess
? fakeFetch
: (uri, opts) => {
try {
validateServer(uri) // Throws for non-Edge servers.
} catch (error) {
return io.fetch(uri, opts)
}
return fakeFetch(uri, opts)
}
const fakeIo = {
...io,
disklet: makeMemoryDisklet(),
fetch
}
// Populate the fake disk:
if (!cleanDevice) {
for (const user of users) {
await saveLogin(fakeIo, user)
for (const syncKey of Object.keys(user.repos)) {
await saveRepo(
fakeIo,
base16.parse(syncKey),
asEdgeRepoDump(user.repos[syncKey])
)
}
}
}
if (extraFiles != null) {
for (const path of Object.keys(extraFiles)) {
await fakeIo.disklet.setText(path, extraFiles[path])
}
}
const out = await makeContext({ io: fakeIo, nativeIo }, logBackend, {
...opts
})
contexts.push(out)
return out
},
async goOffline(offline = true) {
fakeServer.offline = offline
},
async dumpFakeUser(account) {
if (account.appId !== '') {
throw new Error('Only root logins are dumpable.')
}
const loginId = base58.parse(account.rootLoginId)
const loginKey = base58.parse(await account.getLoginKey())
// Find the data on the server:
const login = fakeDb.getLoginById(loginId)
if (login == null) {
throw new Error(`Cannot find user ${account.rootLoginId}`)
}
// Figure out which repos to use:
const syncKeys = []
for (const info of account.allKeys) {
const keys = await account.getRawPrivateKey(info.id)
if (keys.syncKey == null) continue
syncKeys.push(
base16.stringify(base64.parse(keys.syncKey)).toLowerCase()
)
}
const repos = {}
for (const syncKey of syncKeys) {
const repo = fakeDb.repos.get(syncKey)
if (repo != null) repos[syncKey] = wasEdgeRepoDump(repo)
}
return {
lastLogin: account.lastLogin,
loginId: base64.stringify(loginId),
loginKey: base64.stringify(loginKey),
repos,
server: wasEdgeLoginDump(fakeDb.dumpLogin(login)),
username: account.username
}
}
}
bridgifyObject(out)
return out
}