@didtools/cacao
Version:
Typescript library for Ceramic OCAP
202 lines (201 loc) • 8.42 kB
JavaScript
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */ // @ts-nocheck
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 { AccountId, ChainId } from 'caip';
import { fromString } from '@didtools/siwx';
export var ErrorTypes;
(function(ErrorTypes) {
/**Thrown when the `validate()` function can verify the message. */ ErrorTypes["INVALID_SIGNATURE"] = "Invalid signature.";
/**Thrown when the `expirationTime` is present and in the past. */ ErrorTypes["EXPIRED_MESSAGE"] = "Expired message.";
/**Thrown when some required field is missing. */ ErrorTypes["MALFORMED_SESSION"] = "Malformed session.";
})(ErrorTypes || (ErrorTypes = {}));
export var SignatureType;
(function(SignatureType) {
/**EIP-191 signature scheme */ SignatureType["PERSONAL_SIGNATURE"] = "Personal signature";
})(SignatureType || (SignatureType = {}));
export class SiwxMessage {
static fromCacao(cacao) {
const account = AccountId.parse(cacao.p.iss.replace('did:pkh:', ''));
const siwx = new this({
domain: cacao.p.domain,
address: account.address,
uri: cacao.p.aud,
version: cacao.p.version,
chainId: new ChainId(account.chainId).reference
});
if (cacao.p.statement) siwx.statement = cacao.p.statement;
if (cacao.p.nonce) siwx.nonce = cacao.p.nonce;
if (cacao.p.iat) siwx.issuedAt = cacao.p.iat;
if (cacao.p.exp) siwx.expirationTime = cacao.p.exp;
if (cacao.p.nbf) siwx.notBefore = cacao.p.nbf;
if (cacao.p.requestId) siwx.requestId = cacao.p.requestId;
if (cacao.p.resources) siwx.resources = cacao.p.resources;
if (cacao.s) {
if (cacao.s.s) siwx.signature = cacao.s.s;
if (cacao.s.t === 'eip191') siwx.type = "Personal signature";
}
return siwx;
}
toMessage(chain, address) {
return asString(this, chain, address);
}
constructor(param){
/**RFC 4501 dns authority that is requesting the signing. */ _define_property(this, "domain", void 0);
/**Ethereum address performing the signing conformant to capitalization
* encoded checksum specified in EIP-55 where applicable. */ _define_property(this, "address", void 0);
/**Human-readable ASCII assertion that the user will sign, and it must not
* contain `\n`. */ _define_property(this, "statement", undefined);
/**RFC 3986 URI referring to the resource that is the subject of the signing
* (as in the __subject__ of a claim). */ _define_property(this, "uri", void 0);
/**Current version of the message. */ _define_property(this, "version", void 0);
/**Randomized token used to prevent replay attacks, at least 8 alphanumeric
* characters. */ _define_property(this, "nonce", undefined);
/**ISO 8601 datetime string of the current time. */ _define_property(this, "issuedAt", undefined);
/**ISO 8601 datetime string that, if present, indicates when the signed
* authentication message is no longer valid. */ _define_property(this, "expirationTime", undefined);
/**ISO 8601 datetime string that, if present, indicates when the signed
* authentication message will become valid. */ _define_property(this, "notBefore", undefined);
/**System-specific identifier that may be used to uniquely refer to the
* sign-in request. */ _define_property(this, "requestId", undefined);
/**EIP-155 Chain ID to which the session is bound, and the network where
* Contract Accounts must be resolved. */ _define_property(this, "chainId", void 0);
/**List of information or references to information the user wishes to have
* resolved as part of authentication by the relying party. They are
* expressed as RFC 3986 URIs separated by `\n- `. */ _define_property(this, "resources", undefined);
/**Signature of the message signed by the wallet. */ _define_property(this, "signature", undefined);
/**Type of sign message to be generated. */ _define_property(this, "type", void 0);
if (typeof param === 'string') {
const parsedMessage = fromString(param);
this.domain = parsedMessage.domain;
this.address = parsedMessage.address;
this.statement = parsedMessage.statement;
this.uri = parsedMessage.uri;
this.version = parsedMessage.version;
this.nonce = parsedMessage.nonce;
this.issuedAt = parsedMessage.issuedAt;
this.expirationTime = parsedMessage.expirationTime;
this.notBefore = parsedMessage.notBefore;
this.requestId = parsedMessage.requestId;
this.chainId = parsedMessage.chainId;
this.resources = parsedMessage.resources;
} else {
Object.assign(this, param);
}
}
}
export function asLegacyChainIdString(message, chainName) {
const header = `${message.domain} wants you to sign in with your ${chainName} account:`;
const uriField = `URI: ${message.uri}`;
let prefix = [
header,
message.address
].join('\n');
const versionField = `Version: ${message.version}`;
if (!message.nonce) {
message.nonce = (Math.random() + 1).toString(36).substring(4);
}
const nonceField = `Nonce: ${message.nonce}`;
const suffixArray = [
uriField,
versionField,
nonceField
];
if (message.issuedAt) {
Date.parse(message.issuedAt);
}
message.issuedAt = message.issuedAt ? message.issuedAt : new Date().toISOString();
suffixArray.push(`Issued At: ${message.issuedAt}`);
if (message.expirationTime) {
const expiryField = `Expiration Time: ${message.expirationTime}`;
suffixArray.push(expiryField);
}
if (message.notBefore) {
suffixArray.push(`Not Before: ${message.notBefore}`);
}
if (message.requestId) {
suffixArray.push(`Request ID: ${message.requestId}`);
}
if (message.chainId) {
suffixArray.push(`Chain ID: ${message.chainId}`);
}
if (message.resources) {
suffixArray.push([
`Resources:`,
...message.resources.map((x)=>`- ${x}`)
].join('\n'));
}
const suffix = suffixArray.join('\n');
if (message.statement) {
prefix = [
prefix,
message.statement
].join('\n\n');
}
return [
prefix,
suffix
].join('\n\n');
}
export function asString(message, chainName, address) {
const header = `${message.domain} wants you to sign in with your ${chainName} account:`;
const uriField = `URI: ${message.uri}`;
let prefix = [
header,
address || message.address
].join('\n');
const versionField = `Version: ${message.version}`;
if (!message.nonce) {
message.nonce = (Math.random() + 1).toString(36).substring(4);
}
const nonceField = `Nonce: ${message.nonce}`;
const chainIdField = `Chain ID: ${message.chainId}`;
const suffixArray = [
uriField,
versionField,
chainIdField,
nonceField
];
if (message.issuedAt) {
Date.parse(message.issuedAt);
}
message.issuedAt = message.issuedAt ? message.issuedAt : new Date().toISOString();
suffixArray.push(`Issued At: ${message.issuedAt}`);
if (message.expirationTime) {
const expiryField = `Expiration Time: ${message.expirationTime}`;
suffixArray.push(expiryField);
}
if (message.notBefore) {
suffixArray.push(`Not Before: ${message.notBefore}`);
}
if (message.requestId) {
suffixArray.push(`Request ID: ${message.requestId}`);
}
if (message.resources && message.resources.length >= 1) {
suffixArray.push([
`Resources:`,
...message.resources.map((x)=>`- ${x}`)
].join('\n'));
}
const suffix = suffixArray.join('\n');
if (message.statement) {
prefix = [
prefix,
message.statement
].join('\n\n');
}
return [
prefix,
suffix
].join('\n\n');
}