2022-12-05 20:14:56 +00:00
|
|
|
import { strict as assert } from 'node:assert/strict'
|
2023-02-15 11:39:15 +00:00
|
|
|
import type { JWK } from 'wildebeest/backend/src/webpush/jwk'
|
2023-01-18 13:31:50 +00:00
|
|
|
import type { Cache } from 'wildebeest/backend/src/cache'
|
2023-01-13 10:56:24 +00:00
|
|
|
import type { Queue } from 'wildebeest/backend/src/types/queue'
|
2022-12-05 20:14:56 +00:00
|
|
|
import { createClient } from 'wildebeest/backend/src/mastodon/client'
|
|
|
|
import type { Client } from 'wildebeest/backend/src/mastodon/client'
|
|
|
|
import { promises as fs } from 'fs'
|
2023-01-16 13:26:10 +00:00
|
|
|
import * as path from 'path'
|
2022-12-05 20:14:56 +00:00
|
|
|
import { BetaDatabase } from '@miniflare/d1'
|
2023-02-22 16:09:43 +00:00
|
|
|
import * as SQLiteDatabase from 'better-sqlite3'
|
|
|
|
import { type Database } from 'wildebeest/backend/src/database'
|
2023-02-28 16:51:38 +00:00
|
|
|
import d1 from 'wildebeest/backend/src/database/d1'
|
2022-12-05 20:14:56 +00:00
|
|
|
|
|
|
|
export function isUrlValid(s: string) {
|
|
|
|
let url
|
|
|
|
try {
|
|
|
|
url = new URL(s)
|
|
|
|
} catch (err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return url.protocol === 'https:'
|
|
|
|
}
|
|
|
|
|
2023-02-22 16:09:43 +00:00
|
|
|
export async function makeDB(): Promise<Database> {
|
|
|
|
const db = new SQLiteDatabase(':memory:')
|
2022-12-05 20:14:56 +00:00
|
|
|
const db2 = new BetaDatabase(db)!
|
|
|
|
|
|
|
|
// Manually run our migrations since @miniflare/d1 doesn't support it (yet).
|
2023-01-16 13:26:10 +00:00
|
|
|
const migrations = await fs.readdir('./migrations/')
|
|
|
|
|
|
|
|
for (let i = 0, len = migrations.length; i < len; i++) {
|
|
|
|
const content = await fs.readFile(path.join('migrations', migrations[i]), 'utf-8')
|
2023-01-11 15:45:07 +00:00
|
|
|
db.exec(content)
|
2023-01-16 13:26:10 +00:00
|
|
|
}
|
2022-12-05 20:14:56 +00:00
|
|
|
|
2023-02-28 16:51:38 +00:00
|
|
|
const env = { DATABASE: db2 } as any
|
|
|
|
return d1(env)
|
2022-12-05 20:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export function assertCORS(response: Response) {
|
|
|
|
assert(response.headers.has('Access-Control-Allow-Origin'))
|
|
|
|
assert(response.headers.has('Access-Control-Allow-Headers'))
|
|
|
|
}
|
|
|
|
|
|
|
|
export function assertJSON(response: Response) {
|
|
|
|
assert.equal(response.headers.get('content-type'), 'application/json; charset=utf-8')
|
|
|
|
}
|
|
|
|
|
|
|
|
export function assertCache(response: Response, maxge: number) {
|
|
|
|
assert(response.headers.has('cache-control'))
|
|
|
|
assert(response.headers.get('cache-control')!.includes('max-age=' + maxge))
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function streamToArrayBuffer(stream: ReadableStream) {
|
|
|
|
let result = new Uint8Array(0)
|
|
|
|
const reader = stream.getReader()
|
|
|
|
while (true) {
|
|
|
|
const { done, value } = await reader.read()
|
|
|
|
if (done) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
const newResult = new Uint8Array(result.length + value.length)
|
|
|
|
newResult.set(result)
|
|
|
|
newResult.set(value, result.length)
|
|
|
|
result = newResult
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function createTestClient(
|
2023-02-22 16:09:43 +00:00
|
|
|
db: Database,
|
2022-12-05 20:14:56 +00:00
|
|
|
redirectUri: string = 'https://localhost',
|
|
|
|
scopes: string = 'read follow'
|
|
|
|
): Promise<Client> {
|
2023-03-01 15:42:08 +00:00
|
|
|
return createClient(db, 'test client', redirectUri, scopes, 'https://cloudflare.com')
|
2022-12-05 20:14:56 +00:00
|
|
|
}
|
2023-01-13 10:56:24 +00:00
|
|
|
|
|
|
|
type TestQueue = Queue<any> & { messages: Array<any> }
|
|
|
|
|
|
|
|
export function makeQueue(): TestQueue {
|
|
|
|
const messages: Array<any> = []
|
|
|
|
|
|
|
|
return {
|
|
|
|
messages,
|
|
|
|
|
|
|
|
async send(msg: any) {
|
|
|
|
messages.push(msg)
|
|
|
|
},
|
|
|
|
|
|
|
|
async sendBatch(batch: Array<{ body: any }>) {
|
|
|
|
for (let i = 0, len = batch.length; i < len; i++) {
|
|
|
|
messages.push(batch[i].body)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2023-01-18 10:39:47 +00:00
|
|
|
|
2023-01-18 13:31:50 +00:00
|
|
|
export function makeCache(): Cache {
|
|
|
|
const cache: any = {}
|
|
|
|
|
|
|
|
return {
|
|
|
|
async get<T>(key: string): Promise<T | null> {
|
|
|
|
if (cache[key]) {
|
|
|
|
return cache[key] as T
|
|
|
|
} else {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async put<T>(key: string, value: T): Promise<void> {
|
|
|
|
cache[key] = value
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 10:39:47 +00:00
|
|
|
export function isUUID(v: string): boolean {
|
|
|
|
assert.equal(typeof v, 'string')
|
|
|
|
if (v.match('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') === null) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2023-02-15 11:39:15 +00:00
|
|
|
|
|
|
|
export async function generateVAPIDKeys(): Promise<JWK> {
|
|
|
|
const keyPair = (await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, [
|
|
|
|
'sign',
|
|
|
|
'verify',
|
|
|
|
])) as CryptoKeyPair
|
|
|
|
const jwk = (await crypto.subtle.exportKey('jwk', keyPair.privateKey)) as JWK
|
|
|
|
return jwk
|
|
|
|
}
|