@didtools/siwx
Version:
Typescript library for Sign-In With X
107 lines (106 loc) • 4.34 kB
JavaScript
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;
}
}