@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
118 lines (115 loc) • 5.75 kB
JavaScript
import { security } from '../constants.mjs';
import { overwriteFile } from '../resource/file.mjs';
import { getSourceUrl } from '../resource/resource.mjs';
import { getSolidDataset } from '../resource/solidDataset.mjs';
import { getUrl } from '../thing/get.mjs';
import { setIri } from '../thing/set.mjs';
import { setThing, getThing } from '../thing/thing.mjs';
// Copyright Inrupt Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
function getProfileFromProfileDoc(profileDataset, webId) {
const profile = getThing(profileDataset, webId);
if (profile === null) {
throw new Error(`Profile document [${getSourceUrl(profileDataset)}] does not include WebID [${webId}]`);
}
return profile;
}
/**
* Set a JWKS IRI associated with a WebID in a profile document.
*
* @param profileDocument The profile document dataset.
* @param webId The WebID associated with the profile document.
* @param jwksIri The JWKS IRI to be set.
* @returns A modified copy of the profile document, with the JWKS IRI set.
* @since 1.12.0
*/
function setProfileJwks(profileDocument, webId, jwksIri) {
return setThing(profileDocument, setIri(getProfileFromProfileDoc(profileDocument, webId), security.publicKey, jwksIri));
}
/**
* Look for a JWKS IRI optionally advertized from a profile document.
*
* @param profileDocument The profile document.
* @param webId The WebID featured in the profile document.
* @returns The JWKS IRI associated with the WebID, if any.
* @since 1.12.0
*/
function getProfileJwksIri(profileDocument, webId) {
return getUrl(getProfileFromProfileDoc(profileDocument, webId), security.publicKey);
}
const isJwks = (jwksDocument) => {
return typeof jwksDocument.keys !== "undefined";
};
/**
* Fetch a JWKS at a given IRI, and add the given JWK to the obtained key set.
*
* @param jwk The JWK to add to the set.
* @param jwksIri The IRI where the key set should be looked up.
* @param options @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters).
* @returns Promise resolving to a JWKS where the given key has been added.
* @since 1.12.0
*/
async function addJwkToJwks(jwk, jwksIri, options) {
var _a;
const jwksResponse = await ((_a = options === null || options === void 0 ? void 0 : options.fetch) !== null && _a !== void 0 ? _a : fetch)(jwksIri);
if (!jwksResponse.ok) {
throw new Error(`Fetching [${jwksIri}] returned an error: ${jwksResponse.status} ${jwksResponse.statusText}`);
}
try {
const jwksDocument = await jwksResponse.json();
if (!isJwks(jwksDocument)) {
throw new Error(`[${jwksIri}] does not dereference to a valid JWKS: ${JSON.stringify(jwksDocument)}`);
}
return {
keys: [...jwksDocument.keys, jwk],
};
}
catch (e) {
throw new Error(`Parsing the document at [${jwksIri}] failed: ${e}`);
}
}
/**
* Adds a public key to the JWKS listed in the profile associated to the given WebID.
* Retrieves the profile document for the specified WebID and looks up the associated
* JWKS. Having added the given key to the JWKS, this function overwrites the
* previous JWKS so that the new version is saved. This assumes the JWKS is hosted
* at a read-write IRI, such as in a Solid Pod.
*
* @param publicKey The public key value to set.
* @param webId The WebID whose profile document references the key set to which we wish to add the specified public key.
* @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters).
* @since 1.12.0
*/
async function addPublicKeyToProfileJwks(publicKey, webId, options = {}) {
const profileDataset = await getSolidDataset(webId, options);
if (profileDataset === null) {
throw new Error(`The profile document associated with WebID [${webId}] could not be retrieved.`);
}
const jwksIri = getProfileJwksIri(profileDataset, webId);
if (jwksIri === null) {
throw new Error(`No key set is declared for the property [${security.publicKey}] in the profile of [${webId}]`);
}
const updatedJwks = await addJwkToJwks(publicKey, jwksIri, options);
return overwriteFile(jwksIri, new Blob([JSON.stringify(updatedJwks)]), {
contentType: "application/json",
fetch: options.fetch,
});
}
export { addJwkToJwks, addPublicKeyToProfileJwks, getProfileJwksIri, setProfileJwks };