Skip to content

Commit e34b974

Browse files
Copilotcubap
andauthored
Add permission checks to components lacking access control (#383)
* Initial plan * Add permission checks to high-priority and medium-priority components Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> * Fix scope parameters in permission checks for consistency Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: cubap <1119165+cubap@users.noreply.github.com>
1 parent 79e5689 commit e34b974

File tree

7 files changed

+136
-11
lines changed

7 files changed

+136
-11
lines changed

components/manage-layers/index.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import TPEN from "../../api/TPEN.js"
22
import "../../components/manage-pages/index.js"
3+
import CheckPermissions from "../../components/check-permissions/checkPermissions.js"
34

45
class ProjectLayers extends HTMLElement {
56

@@ -9,8 +10,16 @@ class ProjectLayers extends HTMLElement {
910

1011
}
1112

12-
connectedCallback() {
13+
async connectedCallback() {
1314
TPEN.attachAuthentication(this)
15+
16+
// Check if user has view permission
17+
const hasViewAccess = await CheckPermissions.checkViewAccess('LAYER', 'METADATA')
18+
if (!hasViewAccess) {
19+
this.shadowRoot.innerHTML = `<p>You don't have permission to view layers</p>`
20+
return
21+
}
22+
1423
if (TPEN.activeProject?._id) {
1524
this.render()
1625
}
@@ -195,7 +204,15 @@ class ProjectLayers extends HTMLElement {
195204
</div>
196205
`
197206
this.shadowRoot.querySelectorAll(".delete-layer").forEach((button) => {
198-
button.addEventListener("click", (event) => {
207+
button.addEventListener("click", async (event) => {
208+
const hasDeleteAccess = await CheckPermissions.checkDeleteAccess('LAYER', '*')
209+
if (!hasDeleteAccess) {
210+
TPEN.eventDispatcher.dispatch("tpen-toast", {
211+
status: "error",
212+
message: "You don't have permission to delete layers"
213+
})
214+
return
215+
}
199216
if (!confirm("This Layer will be deleted and the Pages will no longer be a part of this project. This action cannot be undone.")) return
200217
const url = event.target.getAttribute("data-layer-id")
201218
const layerId = url.substring(url.lastIndexOf("/") + 1)
@@ -217,7 +234,15 @@ class ProjectLayers extends HTMLElement {
217234
})
218235
})
219236

220-
this.shadowRoot.querySelector(".add-layer").addEventListener("click", () => {
237+
this.shadowRoot.querySelector(".add-layer").addEventListener("click", async () => {
238+
const hasCreateAccess = await CheckPermissions.checkCreateAccess('LAYER', '*')
239+
if (!hasCreateAccess) {
240+
TPEN.eventDispatcher.dispatch("tpen-toast", {
241+
status: "error",
242+
message: "You don't have permission to create layers"
243+
})
244+
return
245+
}
221246
const canvases = []
222247
layers.map(layer => (layer.pages).map(page => {
223248
if (!canvases.includes(page.target) && page.target) {

components/manage-pages/index.js

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import TPEN from "../../api/TPEN.js"
2+
import CheckPermissions from "../../components/check-permissions/checkPermissions.js"
23

34
class ManagePages extends HTMLElement {
45

@@ -7,8 +8,16 @@ class ManagePages extends HTMLElement {
78
this.attachShadow({ mode: "open" })
89
}
910

10-
connectedCallback() {
11+
async connectedCallback() {
1112
TPEN.attachAuthentication(this)
13+
14+
// Check if user has view permission
15+
const hasViewAccess = await CheckPermissions.checkViewAccess('PAGE', 'METADATA')
16+
if (!hasViewAccess) {
17+
this.shadowRoot.innerHTML = `<p>You don't have permission to view pages</p>`
18+
return
19+
}
20+
1221
if (TPEN.activeProject?._id) {
1322
this.render()
1423
}
@@ -99,6 +108,15 @@ class ManagePages extends HTMLElement {
99108
const pages = layers?.pages
100109
this.shadowRoot.querySelectorAll(".manage-pages").forEach((button) => {
101110
button.addEventListener("click", async () => {
111+
// Check if user has edit permission for pages
112+
const hasEditAccess = await CheckPermissions.checkEditAccess('PAGE', 'METADATA')
113+
if (!hasEditAccess) {
114+
TPEN.eventDispatcher.dispatch("tpen-toast", {
115+
status: "error",
116+
message: "You don't have permission to manage pages"
117+
})
118+
return
119+
}
102120
const buttonParent = button.getRootNode().host
103121
const mainParent= buttonParent.getRootNode().host
104122
const layerIndex = buttonParent.getAttribute("data-index")
@@ -174,7 +192,15 @@ class ManagePages extends HTMLElement {
174192
deleteButton.innerText = "Delete Page"
175193
editPageLabelButton.after(deleteButton)
176194

177-
editPageLabelButton.addEventListener("click", () => {
195+
editPageLabelButton.addEventListener("click", async () => {
196+
const hasUpdateAccess = await CheckPermissions.checkEditAccess('PAGE', 'METADATA')
197+
if (!hasUpdateAccess) {
198+
TPEN.eventDispatcher.dispatch("tpen-toast", {
199+
status: "error",
200+
message: "You don't have permission to edit page labels"
201+
})
202+
return
203+
}
178204
labelDiv.classList.add("hidden")
179205
editPageLabelButton.classList.add("hidden")
180206
const labelInput = document.createElement("input")
@@ -227,7 +253,15 @@ class ManagePages extends HTMLElement {
227253
})
228254
})
229255

230-
deleteButton.addEventListener("click", () => {
256+
deleteButton.addEventListener("click", async () => {
257+
const hasDeleteAccess = await CheckPermissions.checkDeleteAccess('PAGE', '*')
258+
if (!hasDeleteAccess) {
259+
TPEN.eventDispatcher.dispatch("tpen-toast", {
260+
status: "error",
261+
message: "You don't have permission to delete pages"
262+
})
263+
return
264+
}
231265
if (!confirm("This Page will be removed from this layer and deleted. This action cannot be undone.")) return
232266
layerCardOuter.querySelector(".layer-pages").removeChild(el)
233267
layers[layerIndex].pages.splice(el.dataset.index, 1)
@@ -255,7 +289,15 @@ class ManagePages extends HTMLElement {
255289
layerActions.insertBefore(saveButton, layerActions.firstChild)
256290
layerActions.removeChild(layerCardOuter.querySelector("tpen-manage-pages"))
257291

258-
editLayerLabelButton.addEventListener("click", () => {
292+
editLayerLabelButton.addEventListener("click", async () => {
293+
const hasUpdateAccess = await CheckPermissions.checkEditAccess('LAYER', 'METADATA')
294+
if (!hasUpdateAccess) {
295+
TPEN.eventDispatcher.dispatch("tpen-toast", {
296+
status: "error",
297+
message: "You don't have permission to edit layer labels"
298+
})
299+
return
300+
}
259301
labelDiv.querySelector(".layer-label").classList.add("hidden")
260302
editLayerLabelButton.classList.add("hidden")
261303
const labelInput = document.createElement("input")
@@ -313,7 +355,15 @@ class ManagePages extends HTMLElement {
313355
})
314356
})
315357

316-
saveButton.addEventListener("click", () => {
358+
saveButton.addEventListener("click", async () => {
359+
const hasUpdateAccess = await CheckPermissions.checkEditAccess('PAGE', 'ORDER')
360+
if (!hasUpdateAccess) {
361+
TPEN.eventDispatcher.dispatch("tpen-toast", {
362+
status: "error",
363+
message: "You don't have permission to reorder pages"
364+
})
365+
return
366+
}
317367
if (!layerCardOuter.querySelector(".layer-pages")?.$isDirty) {
318368
TPEN.eventDispatcher.dispatch("tpen-toast", {"status":"info", "message":"No Changes to Save"})
319369
return

components/project-export/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import TPEN from '../../api/TPEN.js'
22
import { checkIfUrlExists } from '../../utilities/checkIfUrlExists.js'
3+
import CheckPermissions from '../../components/check-permissions/checkPermissions.js'
34

45
customElements.define('tpen-project-export', class extends HTMLElement {
56
constructor() {
@@ -13,6 +14,13 @@ customElements.define('tpen-project-export', class extends HTMLElement {
1314
}
1415

1516
async render() {
17+
// Check if user has view permission
18+
const hasViewAccess = await CheckPermissions.checkViewAccess('PROJECT', 'METADATA')
19+
if (!hasViewAccess) {
20+
this.shadowRoot.innerHTML = `<p>You don't have permission to view project export</p>`
21+
return
22+
}
23+
1624
const url = `${TPEN.staticURL}/${TPEN.activeProject._id}/manifest.json`
1725
const response = await fetch(`${TPEN.servicesURL}/project/${TPEN.activeProject._id}/deploymentStatus`, {
1826
method: 'GET',

components/project-layers/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import TPEN from "../../api/TPEN.js"
2+
import CheckPermissions from "../../components/check-permissions/checkPermissions.js"
23

34
class ProjectLayers extends HTMLElement {
45
constructor() {
@@ -11,7 +12,14 @@ class ProjectLayers extends HTMLElement {
1112
TPEN.eventDispatcher.on('tpen-project-loaded', () => this.render())
1213
}
1314

14-
render() {
15+
async render() {
16+
// Check if user has view permission
17+
const hasViewAccess = await CheckPermissions.checkViewAccess('LAYER', 'METADATA')
18+
if (!hasViewAccess) {
19+
this.shadowRoot.innerHTML = `<p>You don't have permission to view layers</p>`
20+
return
21+
}
22+
1523
const layers = TPEN.activeProject.layers
1624
this.shadowRoot.innerHTML = `
1725
<style>

components/project-metadata/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import TPEN from "../../api/TPEN.js"
2+
import CheckPermissions from "../../components/check-permissions/checkPermissions.js"
23

34
class ProjectMetadata extends HTMLElement {
45
constructor() {
@@ -68,7 +69,15 @@ class ProjectMetadata extends HTMLElement {
6869
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.loadMetadata(TPEN.activeProject))
6970
}
7071

71-
loadMetadata(project) {
72+
async loadMetadata(project) {
73+
// Check if user has view permission
74+
const hasViewAccess = await CheckPermissions.checkViewAccess('PROJECT', 'METADATA')
75+
if (!hasViewAccess) {
76+
const projectMetadata = this.shadowRoot.querySelector(".metadata")
77+
projectMetadata.innerHTML = `<p>You don't have permission to view project metadata</p>`
78+
return
79+
}
80+
7281
let projectMetada = this.shadowRoot.querySelector(".metadata")
7382
const metadata = project.metadata
7483
projectMetada.innerHTML = ""

components/project-permissions/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import TPEN from "../../api/TPEN.js"
2+
import CheckPermissions from "../../components/check-permissions/checkPermissions.js"
23

34
class ProjectPermissions extends HTMLElement {
45
constructor() {
@@ -12,6 +13,13 @@ class ProjectPermissions extends HTMLElement {
1213
}
1314

1415
async render() {
16+
// Check if user has view permission
17+
const hasViewAccess = await CheckPermissions.checkViewAccess('PERMISSION', '*')
18+
if (!hasViewAccess) {
19+
this.shadowRoot.innerHTML = `<p>You don't have permission to view project permissions</p>`
20+
return
21+
}
22+
1523
this.shadowRoot.innerHTML = `
1624
<style>
1725
.roles-list {

components/update-metadata/index.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import TPEN from "../../api/TPEN.js"
22
import User from "../../api/User.js"
33
import { eventDispatcher } from "../../api/events.js"
4+
import CheckPermissions from "../../components/check-permissions/checkPermissions.js"
45

56
class UpdateMetadata extends HTMLElement {
67
constructor() {
@@ -12,7 +13,14 @@ class UpdateMetadata extends HTMLElement {
1213
return ['tpen-user-id']
1314
}
1415

15-
connectedCallback() {
16+
async connectedCallback() {
17+
// Check if user has view permission
18+
const hasViewAccess = await CheckPermissions.checkViewAccess('PROJECT', 'METADATA')
19+
if (!hasViewAccess) {
20+
this.shadowRoot.innerHTML = `<p>You don't have permission to view project metadata</p>`
21+
return
22+
}
23+
1624
this.addEventListener()
1725
TPEN.attachAuthentication(this)
1826
}
@@ -177,6 +185,15 @@ class UpdateMetadata extends HTMLElement {
177185
}
178186

179187
async updateMetadata() {
188+
// Check if user has edit permission
189+
const hasEditAccess = await CheckPermissions.checkEditAccess('PROJECT', 'METADATA')
190+
if (!hasEditAccess) {
191+
return TPEN.eventDispatcher.dispatch("tpen-toast", {
192+
status: "error",
193+
message: "You don't have permission to update project metadata"
194+
})
195+
}
196+
180197
const fields = document.querySelectorAll(".metadata-field")
181198
const updatedMetadata = []
182199

0 commit comments

Comments
 (0)