security hardening, team invites, granular locking, view counts, board subscriptions, scheduled changelog, mentions, recovery codes, accessibility and hover states
This commit is contained in:
34
packages/web/src/lib/altcha.ts
Normal file
34
packages/web/src/lib/altcha.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { api } from './api'
|
||||
|
||||
interface Challenge {
|
||||
algorithm: string
|
||||
challenge: string
|
||||
maxnumber: number
|
||||
salt: string
|
||||
signature: string
|
||||
}
|
||||
|
||||
async function hashHex(algorithm: string, data: string): Promise<string> {
|
||||
const alg = algorithm.replace('-', '').toUpperCase() === 'SHA256' ? 'SHA-256' : algorithm
|
||||
const buf = await crypto.subtle.digest(alg, new TextEncoder().encode(data))
|
||||
return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('')
|
||||
}
|
||||
|
||||
export async function solveAltcha(difficulty: 'normal' | 'light' = 'normal'): Promise<string> {
|
||||
const ch = await api.get<Challenge>(`/altcha/challenge?difficulty=${difficulty}`)
|
||||
|
||||
for (let n = 0; n <= ch.maxnumber; n++) {
|
||||
const hash = await hashHex(ch.algorithm, ch.salt + n)
|
||||
if (hash === ch.challenge) {
|
||||
return btoa(JSON.stringify({
|
||||
algorithm: ch.algorithm,
|
||||
challenge: ch.challenge,
|
||||
number: n,
|
||||
salt: ch.salt,
|
||||
signature: ch.signature,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Failed to solve challenge')
|
||||
}
|
||||
Reference in New Issue
Block a user