(core) apply access control to code view

Summary:
Names of private tables and columns were leaking via Code View.
This plugs that leak.

Test Plan: adds test

Reviewers: dsagal

Reviewed By: dsagal

Differential Revision: https://phab.getgrist.com/D2840
pull/9/head
Paul Fitzpatrick 3 years ago
parent 96fee73b70
commit 37698f9cb5

@ -17,3 +17,7 @@
.g-code-viewer.hljs {
background-color: inherit;
}
.g-code-panel-denied {
text-align: center;
}

@ -14,6 +14,7 @@ hljs.registerLanguage('python', require('highlight.js/lib/languages/python'));
function CodeEditorPanel(gristDoc) {
this._gristDoc = gristDoc;
this._schema = ko.observable('');
this._denied = ko.observable(false);
this.listenTo(this._gristDoc, 'schemaUpdateAction', this.onSchemaAction);
this.onSchemaAction(); // Fetch the schema to initialize
@ -28,6 +29,10 @@ CodeEditorPanel.prototype.buildDom = function() {
// interfere with text selection even for un-focusable elements.
return dom('div.g-code-panel.clipboard',
{tabIndex: "-1"},
kd.maybe(this._denied, () => dom('div.g-code-panel-denied',
dom('h2', kd.text('Access denied')),
dom('div', kd.text('Code View is available only when you have full document access.')),
)),
kd.scope(this._schema, function(schema) {
// The reason to scope and rebuild instead of using `kd.text(schema)` is because
// hljs.highlightBlock(elem) replaces `elem` with a whole new dom tree.
@ -45,13 +50,22 @@ CodeEditorPanel.prototype.buildDom = function() {
);
};
CodeEditorPanel.prototype.onSchemaAction = function(actions) {
return this._gristDoc.docComm.fetchTableSchema()
.then(schema => {
CodeEditorPanel.prototype.onSchemaAction = async function(actions) {
try {
const schema = await this._gristDoc.docComm.fetchTableSchema();
if (!this.isDisposed()) {
this._schema(schema);
this._denied(false);
}
});
} catch (err) {
if (!String(err).match(/Cannot view code/)) {
throw err;
}
if (!this.isDisposed()) {
this._schema('');
this._denied(true);
}
}
};
module.exports = CodeEditorPanel;

@ -658,6 +658,12 @@ export class ActiveDoc extends EventEmitter {
*/
public async fetchTableSchema(docSession: DocSession): Promise<string> {
this.logInfo(docSession, "fetchTableSchema(%s)", docSession);
// Permit code view if user can read everything, or can download/copy (perhaps
// via an exceptional permission for sample documents)
if (!(await this._granularAccess.canReadEverything(docSession) ||
await this.canDownload(docSession))) {
throw new ApiError('Cannot view code, it may contain private material', 403);
}
await this.waitForInitialization();
return this._pyCall('fetch_table_schema');
}

Loading…
Cancel
Save