UNPKG

@acurast/cli

Version:

A cli to interact with the Acurast Cloud.

40 lines 2.02 kB
import { signatureVerify } from '@polkadot/util-crypto'; import { stringToU8a, u8aWrapBytes } from '@polkadot/util'; /** Fixed first line of the login challenge. Lets the hub reject crafted messages. */ export const LOGIN_CHALLENGE_PREFIX = 'Acurast CLI login v1'; /** Challenges older than this are considered stale. */ export const CHALLENGE_MAX_AGE_MS = 10 * 60000; /** * Build the human-readable message the wallet is asked to sign during * `acurast login`. Multi-line so the hub can display it and constrain it to a * known prefix; `issuedAt` is injectable for deterministic tests. */ export const buildLoginChallenge = (nonce, issuedAt = new Date().toISOString()) => `${LOGIN_CHALLENGE_PREFIX}\nChallenge: ${nonce}\nIssued At: ${issuedAt}`; /** Parse + prefix-validate a challenge string. Returns null when malformed. */ export const parseLoginChallenge = (message) => { const lines = message.split('\n'); if (lines[0] !== LOGIN_CHALLENGE_PREFIX) return null; const nonce = lines.find((l) => l.startsWith('Challenge: '))?.slice('Challenge: '.length); const issuedAt = lines.find((l) => l.startsWith('Issued At: '))?.slice('Issued At: '.length); if (!nonce || !issuedAt) return null; return { nonce, issuedAt }; }; /** True when `issuedAt` is recent (allowing a little clock skew). */ export const isChallengeRecent = (issuedAt, maxAgeMs = CHALLENGE_MAX_AGE_MS) => { const t = Date.parse(issuedAt); if (Number.isNaN(t)) return false; const age = Date.now() - t; return age >= -60000 && age <= maxAgeMs; }; /** * Verify the wallet signed exactly `message`. Different providers wrap bytes * differently (`<Bytes>…</Bytes>`), so accept both the raw and wrapped forms. */ export const verifyLoginSignature = (message, signature, address) => { const messageU8a = stringToU8a(message); return [messageU8a, u8aWrapBytes(messageU8a)].some((m) => signatureVerify(m, signature, address).isValid); }; //# sourceMappingURL=loginChallenge.js.map