URLs & RecordIds

So, I have an app that is multi-tenant.

I allow users from client A to view (some) records from client B. However, when the user from client A edits one of their own records, they can paste (in the browser bar) the recordId from any client B record and view / edit / delete that record.

I want my users to be able only edit (in ANY way - UI and browser bar) records from their own client - and no others. They can see the recordId of any record in Knack when they hover over a button to view it.

Anyone figured this out?

Best - Ty

Ty: this is something I never noticed that can be done. I tested it on my end and I was able to edit/delete another record.
I asked ChatGPT to come up with custom code to mask the record ID from those buttons/links for my entire app. I tested it and it is working for me.

Maybe it can work for you.

// ============================================================
// GLOBAL - Hide Knack Record IDs When Hovering Over Links
// ============================================================

(function () {

// Knack record IDs are normally 24-character hexadecimal IDs
var recordIdPattern = /[a-f0-9]{24}/i;

function getLink(target) {
    if (!target || !target.closest) return null;
    return target.closest('a');
}

function isRecordLink(link) {

    if (!link) return false;

    var href = link.getAttribute('href');

    if (!href) return false;

    // Ignore non-navigation links
    if (
        href.indexOf('mailto:') === 0 ||
        href.indexOf('tel:') === 0 ||
        href.indexOf('javascript:') === 0
    ) {
        return false;
    }

    return recordIdPattern.test(href);
}

function maskLink(link) {

    // Already masked
    if (link.hasAttribute('data-bcc-original-href')) {
        return;
    }

    var href = link.getAttribute('href');

    if (!href || !isRecordLink(link)) {
        return;
    }

    // Save the real destination
    link.setAttribute('data-bcc-original-href', href);

    // Replace it while hovering so the record ID
    // does not appear in the browser status bar
    link.setAttribute('href', '#');
}

function restoreLink(link) {

    if (!link) return;

    var originalHref =
        link.getAttribute('data-bcc-original-href');

    if (!originalHref) return;

    link.setAttribute('href', originalHref);
    link.removeAttribute('data-bcc-original-href');
}


// ----------------------------------------------------------
// MASK WHEN USER HOVERS OVER A LINK
// ----------------------------------------------------------

document.addEventListener('mouseover', function (event) {

    var link = getLink(event.target);

    if (!link) return;

    maskLink(link);

}, true);


// ----------------------------------------------------------
// RESTORE WHEN USER LEAVES THE LINK
// ----------------------------------------------------------

document.addEventListener('mouseout', function (event) {

    var link = getLink(event.target);

    if (!link) return;

    // Make sure we're actually leaving the link
    if (
        event.relatedTarget &&
        link.contains(event.relatedTarget)
    ) {
        return;
    }

    restoreLink(link);

}, true);


// ----------------------------------------------------------
// RESTORE BEFORE KNACK PROCESSES THE CLICK
// ----------------------------------------------------------

document.addEventListener('click', function (event) {

    var link = getLink(event.target);

    if (!link) return;

    restoreLink(link);

}, true);


// Support middle-click as well
document.addEventListener('auxclick', function (event) {

    var link = getLink(event.target);

    if (!link) return;

    restoreLink(link);

}, true);

})();

Thanks! I’ll give it a shot!

So this works great! Thanks so much. We all still have the conundrum of a bad actor being able to view any record, press F12, and see the recordId in the JS. They can paste it in the url bar and do anything with the record. I know the plan to add DAC, but I don’t know if it allows group level controls (“this is in my department / client so I can see / edit”) or (“I created the record so I can see / edit it”).

My workflow for that is setting up page rules and hiding details views when they do not have the role to edit or delete a record, even when they can see it. Have you tried this?

For example: create a role for client A and client B, if you don’t have it already. Assign the role to the client A so that when they view a record that belongs to Client B, they cannot edit or delete it. You would use (does not contain “role name”) You will have to create new details view for just the edit and delete buttons. I would create separate detail views for each button so that you can customize the roles later if you want.

You will need to use a field, if you don’t have one already, that can tell the page rule that this record is from Client A or B.

Hope this helps. :slight_smile: