Working with default access

Hi, I’m trying to create an app with all its data located in /app-folder. As a user I want to give access to other users to read/write to this folder based on their webId. From my understanding, I should use the unviersalAccess package provided by inrupt, but this only has methods for changing access to a specific resource. I want to be able to set access for the folder and all its children. I have also tried using the ‘setAgentDefaultAccess’ from the acl/agent module. When setting the acl it’s seems to have the right accesses, but when I try to read the dataset with the acl later, I get that it has no acl available. Have anyone run into the same problems and know what I’m doing wrong?

The code where I generate the container and set the access:

export async function createAppProfile(
  session: Session | null,
  name: string = '',
  email: string = ''
) {
  if (!session) {
    throw new Error('No session found');
  }
  const pod = await getPodUrl(session);

  const fullBaseUrl = `${pod}${BASE_APP_CONTAINER}`;
  await createContainerAt(fullBaseUrl, {
    fetch: session.fetch,
  });

  const { datasetWithAcl, acl } = await getOrCreateDatasetWithAcl(
    fullBaseUrl,
    session
  );

  const newAcl = setAgentResourceAccess(
    setAgentDefaultAccess(acl, session.info.webId!, {
      read: true,
      write: true,
      append: true,
      control: true,
    }),
    session.info.webId!,
    { read: true, write: true, append: true, control: true } // Add resource access
  );

  console.log('[Create profile] New acl: ', newAcl);

  await saveAclFor(datasetWithAcl, newAcl, { fetch: session.fetch });

  let appProfileSolidDataset = createSolidDataset();

  const appProfile = buildThing(createThing({ name: 'profile' }))
    .addUrl(RDF.type, PROFILE_SCHEMA.person)
    .addStringNoLocale(PROFILE_SCHEMA.name, name)
    .addStringNoLocale(PROFILE_SCHEMA.email, email)
    .addStringNoLocale(PROFILE_SCHEMA.teamUrl, '')
    .build();

  appProfileSolidDataset = setThing(appProfileSolidDataset, appProfile);

  await saveSolidDatasetAt(
    `${pod}/${BASE_APP_CONTAINER}/Profile`,
    appProfileSolidDataset,
    { fetch: session.fetch }
  );
}

The ‘getOrCreateDatasetWithAcl’ is a function that uses the example code from the docs:

export async function getOrCreateDatasetWithAcl(url: string, session: Session) {
  const datasetWithAcl = await getSolidDatasetWithAcl(url, {
    fetch: session.fetch,
  });

  let acl;
  if (!hasResourceAcl(datasetWithAcl)) {
    if (!hasAccessibleAcl(datasetWithAcl)) {
      throw new Error(
        'The current user does not have permission to change access rights to this folder.'
      );
    }
    if (!hasFallbackAcl(datasetWithAcl)) {
      acl = createAcl(datasetWithAcl);
    } else {
      acl = createAclFromFallbackAcl(datasetWithAcl);
    }
  } else {
    acl = getResourceAcl(datasetWithAcl);
  }
  return { datasetWithAcl, acl };
}

From debugging, it looks like this always ends up creating a new acl.

Finally, I have this function that tries to fetch the newly created container with the acl:

async function getPermissions(session: Session) {
  const podUrl = await getPodUrl(session);

  const { acl } = await getOrCreateDatasetWithAcl(
    `${podUrl}${BASE_APP_CONTAINER}`,
    session
  );

  console.log('[Fetch members with permissions] Acl: ', acl);
  const res = getAgentDefaultAccessAll(acl);
  console.log('[Fetch members with permissions] Res: ', res);

  return res;
}

Again, the ‘getOrCreateDatasetWithAcl’ looks to always end up in the block where it creates a new acl, even though I create and save one in the first method

I don’t have the bandwidth to look over your code currently but in the Solid ACL spec, if a parent resource has an acl and a child does not, the child resource should inherit the parent resource’s permissions.

One problem that could be occurring in your code is this line right here:
await saveAclFor(datasetWithAcl, newAcl, { fetch: session.fetch });

This API returns an AclDataset, which is a SolidDataset plus extra information. You should probably be taking the returned object and setting your appProfileThing in the return of this, and then save it.

Thanks for your reply. I tried to set the profile thing to the return of saveAclFor but this just gives me a type error.

The main question I’m asking I guess is, how can I create a base container for my application and set a default permission on this container so that all resources in this container will inherit the permissions? Then as a follow up, how can I read these permissions later when they are set?