chore: update public repo

This commit is contained in:
desu-bot 2026-01-01 18:52:50 +00:00
parent ef375d1188
commit 46cf487f04
No known key found for this signature in database
5 changed files with 229 additions and 26 deletions

99
scripts/misc/ap-signed.ts Normal file
View file

@ -0,0 +1,99 @@
import crypto from 'node:crypto'
import { question } from 'zx'
import { ffetch } from '../../utils/fetch.ts'
import { getEnv } from '../../utils/misc.ts'
function bigintToBase64Url(bn) {
let hex = bn.toString(16)
if (hex.length % 2) hex = `0${hex}`
// eslint-disable-next-line no-restricted-globals
const buf = Buffer.from(hex, 'hex')
return buf.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}
interface GoPrivateKey {
N: bigint
E: bigint
D: bigint
Primes: [bigint, bigint]
Precomputed?: {
Dp?: bigint
Dq?: bigint
Qinv?: bigint
}
}
function goKeyToPEM(goKey: GoPrivateKey) {
const jwk = {
kty: 'RSA',
n: bigintToBase64Url(goKey.N),
e: bigintToBase64Url(goKey.E),
d: bigintToBase64Url(goKey.D),
p: bigintToBase64Url(goKey.Primes[0]),
q: bigintToBase64Url(goKey.Primes[1]),
dp: goKey.Precomputed?.Dp ? bigintToBase64Url(goKey.Precomputed.Dp) : undefined,
dq: goKey.Precomputed?.Dq ? bigintToBase64Url(goKey.Precomputed.Dq) : undefined,
qi: goKey.Precomputed?.Qinv ? bigintToBase64Url(goKey.Precomputed.Qinv) : undefined,
}
// Remove undefined fields (dp/dq/qi could be missing if not precomputed)
Object.keys(jwk).forEach(k => jwk[k] === undefined && delete jwk[k])
const keyObject = crypto.createPrivateKey({ key: jwk, format: 'jwk' })
return keyObject.export({ type: 'pkcs8', format: 'pem' })
}
// ! currently only supports gts privkey format, but should be easy enough to support other key formats
const privKey = goKeyToPEM(JSON.parse(getEnv('AP_PRIVKEY'), ((key, value, ctx) => {
// go privkey json stores long numbers as just numbers so we need to convert them to bigints. requires node 20+ i think
if (typeof value === 'number') return BigInt(ctx.source)
return value
}) as any))
const actor = getEnv('AP_ACTOR')
const url = new URL(process.argv[2] ?? (await question('url > ')))
const body = (process.argv[3] ?? (await question('body (empty for GET) > '))).trim()
const host = url.host
const path = url.pathname
const method = body ? 'POST' : 'GET'
const date = new Date().toUTCString()
const digest = body ? `SHA-256=${crypto.createHash('sha256').update(body).digest('base64')}` : undefined
let toSign = `(request-target): ${method.toLowerCase()} ${path}
host: ${host}
date: ${date}`
if (body) {
toSign += `\ndigest: ${digest}`
}
const signature = crypto.createSign('RSA-SHA256').update(toSign).sign(privKey, 'base64')
const headers: Record<string, string> = {
'Date': date,
'Signature': `keyId="${actor}#main-key",headers="(request-target) host date${body ? ' digest' : ''}",algorithm="rsa-sha256",signature="${signature}"`,
'Content-Type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
}
if (body) {
headers.Digest = digest!
}
const res = await ffetch(`https://${host}${path}`, {
headers,
method,
body: body || undefined,
validateResponse: false,
})
console.log(res.status)
const resText = await res.text()
if (resText[0] !== '{') {
console.error('bad response:', resText)
process.exit(1)
}
const json = JSON.parse(resText)
console.dir(json, { depth: null })