From d4effb3191f1f9dcb13b7df4e41ea6f7481c52dc Mon Sep 17 00:00:00 2001 From: smessie Date: Mon, 7 Nov 2022 14:33:43 +0100 Subject: [PATCH] fix: Rewrite getPodBase to always get correct podBase The new algorithm uses a combination of looking at the response headers to see if the current resource is the podBase, as defined by [`Clients can determine the storage of a resource by moving up the URI path hierarchy until the response includes a Link header with rel="type" targeting http://www.w3.org/ns/pim/space#Storage.`](https://solidproject.org/TR/protocol#storage), and at the same time also looking if there is a pim:Storage (as object) triple in the resource stating that this resource is the podBase; as some server implementations use this technique. Lastly, it also checks if there is a pim:storage (as predicate) triple in the resource, defining where the podBase is stored, used e.g. in the WebID resource on ESS. --- addon/services/solid-auth.js | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/addon/services/solid-auth.js b/addon/services/solid-auth.js index 174e3e8..a930866 100644 --- a/addon/services/solid-auth.js +++ b/addon/services/solid-auth.js @@ -180,14 +180,32 @@ export default class AuthService extends Service { let webIdDoc = webId; if (webId) { await this.store.load(sym(webId).doc()); - podBase = this.store.any(sym(webId), SP('storage'), undefined, sym(webIdDoc).doc())?.value || this.store.any(undefined, RDF('type'), SP('Storage'), sym(webIdDoc).doc())?.value; - // Check if podBase is not undefined and webIdDoc is not the root domain + + // Start with WebID and traverse upwards until we find a pim:Storage resource or a pim:Storage link response header. let previousWebIdDoc = webIdDoc; - while (!podBase && !this.store.any(webIdDoc, RDF('type'), LDP('BasicContainer'), sym(webIdDoc).doc()) && !webIdDoc.endsWith('://')) { - // Substring of webIdDoc leaving off the last slash and last directory. - previousWebIdDoc = webIdDoc; - webIdDoc = webIdDoc.substring(0, webIdDoc.lastIndexOf('/', webIdDoc.length - 2)) + '/'; - podBase = this.store.any(sym(webIdDoc), SP('storage'), undefined, sym(webIdDoc).doc())?.value || this.store.any(undefined, RDF('type'), SP('Storage'), sym(webIdDoc).doc())?.value; + while (!podBase && !this.store.any(webIdDoc, RDF("type"), LDP("BasicContainer"), sym(webIdDoc).doc()) && !webIdDoc.endsWith("://")) { + // Check if the current resource is a pim:Storage resource + podBase = this.store.any(sym(webIdDoc), SP("storage"), undefined, sym(webIdDoc).doc())?.value || this.store.any(undefined, RDF("type"), SP("Storage"), sym(webIdDoc).doc())?.value; + + // Otherwise, check if the current resource has a pim:Storage link response header. + if (!podBase) { + // Get response headers from the webIdDoc + const response = await fetch(webIdDoc, { method: 'HEAD' }); + const linkHeader = response.headers.get('Link'); + if ( + linkHeader && + linkHeader.includes('http://www.w3.org/ns/pim/space#Storage') + ) { + podBase = webIdDoc; + } + } + + // Otherwise, traverse upwards + if (!podBase) { + // Prepare next iteration + previousWebIdDoc = webIdDoc; + webIdDoc = webIdDoc.substring(0, webIdDoc.lastIndexOf("/", webIdDoc.length - 2)) + "/"; + } } if (!podBase) {