@sphereon/oid4vci-common
Version:
OpenID 4 Verifiable Credential Issuance Common Types
168 lines • 7.34 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getURIComponentsAsArray = exports.decodeJsonProperties = exports.convertURIToJsonObject = exports.convertJsonToURI = void 0;
const types_1 = require("../types");
/**
* @type {(json: {[s:string]: never} | ArrayLike<never> | string | object, opts?: EncodeJsonAsURIOpts)} encodes a Json object into a URI
* @param { {[s:string]: never} | ArrayLike<never> | string | object } json
* @param {EncodeJsonAsURIOpts} [opts] Option to encode json as uri
* - urlTypeProperties: a list of properties of which the value is a URL
* - arrayTypeProperties: a list of properties which are an array
*/
// /* eslint-disable @typescript-eslint/no-explicit-any */
function convertJsonToURI(json, opts) {
var _a, _b;
if (typeof json === 'string') {
return convertJsonToURI(JSON.parse(json), opts);
}
const results = [];
function encodeAndStripWhitespace(key) {
return encodeURIComponent(key.replace(' ', ''));
}
let components;
if (((opts === null || opts === void 0 ? void 0 : opts.version) && opts.version > types_1.OpenId4VCIVersion.VER_1_0_08 && !opts.mode) || (opts === null || opts === void 0 ? void 0 : opts.mode) === types_1.JsonURIMode.JSON_STRINGIFY) {
// v11 changed from encoding every param to a encoded json object with a credential_offer param key
components = encodeAndStripWhitespace(JSON.stringify(json));
}
else {
// version 8 or lower, or mode is x-form-www-urlencoded
for (const [key, value] of Object.entries(json)) {
if (!value) {
continue;
}
//Skip properties that are not of URL type
if (!((_a = opts === null || opts === void 0 ? void 0 : opts.uriTypeProperties) === null || _a === void 0 ? void 0 : _a.includes(key))) {
results.push(`${key}=${value}`);
continue;
}
if (((_b = opts === null || opts === void 0 ? void 0 : opts.arrayTypeProperties) === null || _b === void 0 ? void 0 : _b.includes(key)) && Array.isArray(value)) {
results.push(value.map((v) => `${encodeAndStripWhitespace(key)}=${customEncodeURIComponent(v, /\./g)}`).join('&'));
continue;
}
const isBool = typeof value == 'boolean';
const isNumber = typeof value == 'number';
const isString = typeof value == 'string';
let encoded;
if (isBool || isNumber) {
encoded = `${encodeAndStripWhitespace(key)}=${value}`;
}
else if (isString) {
encoded = `${encodeAndStripWhitespace(key)}=${customEncodeURIComponent(value, /\./g)}`;
}
else {
encoded = `${encodeAndStripWhitespace(key)}=${customEncodeURIComponent(JSON.stringify(value), /\./g)}`;
}
results.push(encoded);
}
components = results.join('&');
}
if (opts === null || opts === void 0 ? void 0 : opts.baseUrl) {
if (opts.baseUrl.endsWith('=')) {
if (opts.param) {
throw Error('Cannot combine param with an url ending in =');
}
return `${opts.baseUrl}${components}`;
}
else if (!opts.baseUrl.includes('?')) {
return `${opts.baseUrl}?${opts.param ? opts.param + '=' : ''}${components}`;
}
else if (opts.baseUrl.endsWith('?')) {
return `${opts.baseUrl}${opts.param ? opts.param + '=' : ''}${components}`;
}
else {
return `${opts.baseUrl}${opts.param ? '&' + opts.param : ''}=${components}`;
}
}
return components;
}
exports.convertJsonToURI = convertJsonToURI;
/**
* @type {(uri: string, opts?: DecodeURIAsJsonOpts): unknown} convertURIToJsonObject converts an URI into a Json object decoding its properties
* @param {string} uri
* @param {DecodeURIAsJsonOpts} [opts]
* - requiredProperties: the required properties
* - arrayTypeProperties: properties that can show up more that once
* @returns JSON object
*/
function convertURIToJsonObject(uri, opts) {
var _a;
if (!uri || ((opts === null || opts === void 0 ? void 0 : opts.requiredProperties) && !((_a = opts.requiredProperties) === null || _a === void 0 ? void 0 : _a.every((p) => uri.includes(p))))) {
throw new Error(types_1.BAD_PARAMS);
}
const uriComponents = getURIComponentsAsArray(uri, opts === null || opts === void 0 ? void 0 : opts.arrayTypeProperties);
return decodeJsonProperties(uriComponents);
}
exports.convertURIToJsonObject = convertURIToJsonObject;
function decodeJsonProperties(parts) {
const result = {};
for (const key in parts) {
const value = parts[key];
if (!value) {
continue;
}
if (Array.isArray(value)) {
result[decodeURIComponent(key)] = value.map((v) => decodeURIComponent(v));
continue;
}
const isBool = typeof value == 'boolean';
const isNumber = typeof value == 'number';
const isString = typeof value == 'string';
const isObject = typeof value == 'object';
if (isBool || isNumber) {
result[decodeURIComponent(key)] = value;
}
else if (isString) {
const decoded = decodeURIComponent(value);
if (decoded.startsWith('{') && decoded.endsWith('}')) {
result[decodeURIComponent(key)] = JSON.parse(decoded);
}
else {
result[decodeURIComponent(key)] = decoded;
}
}
else if (isObject) {
result[decodeURIComponent(key)] = decodeJsonProperties(value);
}
}
return result;
}
exports.decodeJsonProperties = decodeJsonProperties;
/**
* @function get URI Components as Array
* @param {string} uri uri
* @param {string[]} [arrayTypes] array of string containing array like keys
*/
function getURIComponentsAsArray(uri, arrayTypes) {
const parts = uri.includes('?') ? uri.split('?')[1] : uri.includes('://') ? uri.split('://')[1] : uri;
const json = [];
const dict = parts.split('&');
for (const entry of dict) {
const pair = entry.split('=');
const p0 = pair[0];
const p1 = pair[1];
if (arrayTypes === null || arrayTypes === void 0 ? void 0 : arrayTypes.includes(p0)) {
const key = json[p0];
if (Array.isArray(key)) {
key.push(p1);
}
else {
json[p0] = [p1];
}
continue;
}
json[p0] = p1;
}
return json;
}
exports.getURIComponentsAsArray = getURIComponentsAsArray;
/**
* @function customEncodeURIComponent is used to encode chars that are not encoded by default
* @param searchValue The pattern/regexp to find the char(s) to be encoded
* @param uriComponent query string
*/
function customEncodeURIComponent(uriComponent, searchValue) {
// -_.!~*'() are not escaped because they are considered safe.
// Add them to the regex as you need
return encodeURIComponent(uriComponent).replace(searchValue, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
}
//# sourceMappingURL=Encoding.js.map