UNPKG

@didtools/siwx

Version:

Typescript library for Sign-In With X

107 lines (106 loc) 4.34 kB
function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { toDateTimeString, toDomainString, toURIString, toVersionString, toChainIdString, toNonceString, toNonEmptyString } from './fields.js'; import { siwxMessage } from './parsing/siwx-message.js'; import { StringTape, parseAll } from 'codeco/linear'; import { isLeft, right, getOrThrow } from 'codeco'; function resourcesList(resources) { return resources.map((r)=>`- ${r}`).join(`\n`); } export class SiwxMessage { toString() { return toString(this); } constructor(fields){ _define_property(this, "domain", void 0); _define_property(this, "network", void 0); _define_property(this, "address", void 0); _define_property(this, "statement", void 0); _define_property(this, "uri", void 0); _define_property(this, "version", void 0); _define_property(this, "chainId", void 0); _define_property(this, "nonce", void 0); _define_property(this, "issuedAt", void 0); _define_property(this, "expirationTime", void 0); _define_property(this, "notBefore", void 0); _define_property(this, "requestId", void 0); _define_property(this, "resources", void 0); this.domain = toDomainString(fields.domain); this.network = toNonEmptyString(fields.network, 'network'); this.address = toNonEmptyString(fields.address, 'address'); this.statement = mapUndefined(fields.statement, (s)=>toNonEmptyString(s, 'statement')); this.uri = toURIString(fields.uri); this.version = toVersionString(fields.version || '1'); this.chainId = toChainIdString(fields.chainId); this.nonce = toNonceString(fields.nonce); this.issuedAt = toDateTimeString(fields.issuedAt); this.expirationTime = mapUndefined(fields.expirationTime, toDateTimeString); this.notBefore = mapUndefined(fields.notBefore, toDateTimeString); this.requestId = mapUndefined(fields.requestId, (s)=>toNonEmptyString(s, 'requestId')); this.resources = mapUndefined(fields.resources, (resources)=>resources.map(toURIString)); } } /** * Parse SIWx message string. * @throws If invalid string passed. */ _define_property(SiwxMessage, "fromString", fromString); /** * Parse SIWx message string. Return `Maybe`, thus do not throw. */ _define_property(SiwxMessage, "fromStringSafe", fromStringSafe); export function fromStringSafe(input) { const parser = parseAll(siwxMessage); const fields = parser(new StringTape(input)); if (isLeft(fields)) return fields; return right(new SiwxMessage(fields.right)); } export function fromString(input) { return getOrThrow(fromStringSafe(input)); } export function toString(message) { const want = `${message.domain} wants you to sign in with your ${message.network} account:`; const address = message.address; const statement = message.statement; const uri = `URI: ${message.uri}`; const version = `Version: ${message.version}`; const chainId = `Chain ID: ${message.chainId}`; const nonce = `Nonce: ${message.nonce}`; const issuedAt = `Issued At: ${message.issuedAt}`; const expirationTime = message.expirationTime ? `Expiration Time: ${message.expirationTime}` : undefined; const notBefore = message.notBefore ? `Not Before: ${message.notBefore}` : undefined; const requestId = message.requestId ? `Request ID: ${message.requestId}` : undefined; const resources = message.resources ? `Resources:\n${resourcesList(message.resources)}` : undefined; let header = `${want}\n${address}\n\n`; if (statement) header += `${statement}\n`; return [ header, uri, version, chainId, nonce, issuedAt, expirationTime, notBefore, requestId, resources ].filter(Boolean).join('\n'); } /** * If `field` is defined, return `fn(field)`. */ function mapUndefined(field, fn) { if (field !== undefined) { return fn(field); } else { return undefined; } }