|
|
|
import { ParsedMessage } from '@spruceid/siwe-parser';
|
|
|
|
import log from 'loglevel';
|
|
|
|
import { stripHexPrefix } from './hexstring-utils';
|
|
|
|
|
|
|
|
const msgHexToText = (hex) => {
|
|
|
|
try {
|
|
|
|
const stripped = stripHexPrefix(hex);
|
|
|
|
const buff = Buffer.from(stripped, 'hex');
|
|
|
|
return buff.length === 32 ? hex : buff.toString('utf8');
|
|
|
|
} catch (e) {
|
|
|
|
log.error(e);
|
|
|
|
return hex;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A locally defined object used to provide data to identify a Sign-In With Ethereum (SIWE)(EIP-4361) message and provide the parsed message
|
|
|
|
*
|
|
|
|
* @typedef localSIWEObject
|
|
|
|
* @param {boolean} isSIWEMessage - Does the intercepted message conform to the SIWE specification?
|
|
|
|
* @param {ParsedMessage} parsedMessage - The data parsed out of the message
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function intercepts a sign message, detects if it's a
|
|
|
|
* Sign-In With Ethereum (SIWE)(EIP-4361) message, and returns an object with
|
|
|
|
* relevant SIWE data.
|
|
|
|
*
|
|
|
|
* {@see {@link https://eips.ethereum.org/EIPS/eip-4361}}
|
|
|
|
*
|
|
|
|
* @param {object} msgParams - The params of the message to sign
|
|
|
|
* @returns {localSIWEObject}
|
|
|
|
*/
|
|
|
|
export const detectSIWE = (msgParams) => {
|
|
|
|
try {
|
|
|
|
const { data } = msgParams;
|
|
|
|
const message = msgHexToText(data);
|
|
|
|
const parsedMessage = new ParsedMessage(message);
|
|
|
|
|
|
|
|
return {
|
|
|
|
isSIWEMessage: true,
|
|
|
|
parsedMessage,
|
|
|
|
};
|
|
|
|
} catch (error) {
|
|
|
|
// ignore error, it's not a valid SIWE message
|
|
|
|
return {
|
|
|
|
isSIWEMessage: false,
|
|
|
|
parsedMessage: null,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes in a parsed Sign-In with Ethereum Message (EIP-4361)
|
|
|
|
* and generates an array of label-value pairs
|
|
|
|
*
|
|
|
|
* @param {object} parsedMessage - A parsed SIWE message with message contents
|
|
|
|
* @param {Function} t - i18n function
|
|
|
|
* @returns {Array} An array of label-value pairs with the type of the value as the label
|
|
|
|
*/
|
|
|
|
export const formatMessageParams = (parsedMessage, t) => {
|
|
|
|
const output = [];
|
|
|
|
|
|
|
|
const {
|
|
|
|
statement,
|
|
|
|
uri,
|
|
|
|
version,
|
|
|
|
chainId,
|
|
|
|
nonce,
|
|
|
|
issuedAt,
|
|
|
|
expirationTime,
|
|
|
|
notBefore,
|
|
|
|
requestId,
|
|
|
|
resources,
|
|
|
|
} = parsedMessage;
|
|
|
|
|
|
|
|
if (statement) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelMessage'),
|
|
|
|
value: statement,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uri) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelURI'),
|
|
|
|
value: uri,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelVersion'),
|
|
|
|
value: version,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chainId) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelChainID'),
|
|
|
|
value: chainId,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nonce) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelNonce'),
|
|
|
|
value: nonce,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (issuedAt) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelIssuedAt'),
|
|
|
|
value: issuedAt,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (expirationTime) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelExpirationTime'),
|
|
|
|
value: expirationTime,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (notBefore) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelNotBefore'),
|
|
|
|
value: notBefore,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (requestId) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelRequestID'),
|
|
|
|
value: requestId,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resources && resources.length > 0) {
|
|
|
|
output.push({
|
|
|
|
label: t('SIWELabelResources', [resources.length]),
|
|
|
|
value: resources
|
|
|
|
.reduce((previous, resource) => `${previous}${resource}\n`, '')
|
|
|
|
.trim(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
};
|