Skip to content

Commit f2d9203

Browse files
authored
Prevent non owners from editing shared snippets (supabase#30692)
* Prevent non owners from editing shared snippets * Add guard against saving snippet which is shared + has folder id * FIX
1 parent 3e7a0df commit f2d9203

File tree

2 files changed

+98
-69
lines changed

2 files changed

+98
-69
lines changed

apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
88
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
99
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
1010
import { useProfile } from 'lib/profile'
11+
import { useAppStateSnapshot } from 'state/app-state'
1112
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
1213
import { cn } from 'ui'
14+
import { Admonition } from 'ui-patterns'
15+
import { useIsAssistantV2Enabled } from '../App/FeaturePreview/FeaturePreviewContext'
1316
import { untitledSnippetTitle } from './SQLEditor.constants'
1417
import type { IStandaloneCodeEditor } from './SQLEditor.types'
1518
import { createSqlSnippetSkeletonV2 } from './SQLEditor.utils'
16-
import { useIsAssistantV2Enabled } from '../App/FeaturePreview/FeaturePreviewContext'
17-
import { useAppStateSnapshot } from 'state/app-state'
1819

1920
export type MonacoEditorProps = {
2021
id: string
@@ -50,6 +51,8 @@ const MonacoEditor = ({
5051
)
5152

5253
const snippet = snapV2.snippets[id]
54+
const disableEdit =
55+
snippet?.snippet.visibility === 'project' && snippet?.snippet.owner_id !== profile?.id
5356

5457
const executeQueryRef = useRef(executeQuery)
5558
executeQueryRef.current = executeQuery
@@ -152,57 +155,68 @@ const MonacoEditor = ({
152155
}, [])
153156

154157
return (
155-
<Editor
156-
className={cn(className, 'monaco-editor')}
157-
theme={'supabase'}
158-
onMount={handleEditorOnMount}
159-
onChange={handleEditorChange}
160-
defaultLanguage="pgsql"
161-
defaultValue={snippet?.snippet.content.sql}
162-
path={id}
163-
options={{
164-
tabSize: 2,
165-
fontSize: 13,
166-
minimap: { enabled: false },
167-
wordWrap: 'on',
168-
// [Joshen] Commenting the following out as it causes the autocomplete suggestion popover
169-
// to be positioned wrongly somehow. I'm not sure if this affects anything though, but leaving
170-
// comment just in case anyone might be wondering. Relevant issues:
171-
// - https://github.com/microsoft/monaco-editor/issues/2229
172-
// - https://github.com/microsoft/monaco-editor/issues/2503
173-
// fixedOverflowWidgets: true,
174-
suggest: {
175-
showMethods: intellisenseEnabled,
176-
showFunctions: intellisenseEnabled,
177-
showConstructors: intellisenseEnabled,
178-
showDeprecated: intellisenseEnabled,
179-
showFields: intellisenseEnabled,
180-
showVariables: intellisenseEnabled,
181-
showClasses: intellisenseEnabled,
182-
showStructs: intellisenseEnabled,
183-
showInterfaces: intellisenseEnabled,
184-
showModules: intellisenseEnabled,
185-
showProperties: intellisenseEnabled,
186-
showEvents: intellisenseEnabled,
187-
showOperators: intellisenseEnabled,
188-
showUnits: intellisenseEnabled,
189-
showValues: intellisenseEnabled,
190-
showConstants: intellisenseEnabled,
191-
showEnums: intellisenseEnabled,
192-
showEnumMembers: intellisenseEnabled,
193-
showKeywords: intellisenseEnabled,
194-
showWords: intellisenseEnabled,
195-
showColors: intellisenseEnabled,
196-
showFiles: intellisenseEnabled,
197-
showReferences: intellisenseEnabled,
198-
showFolders: intellisenseEnabled,
199-
showTypeParameters: intellisenseEnabled,
200-
showIssues: intellisenseEnabled,
201-
showUsers: intellisenseEnabled,
202-
showSnippets: intellisenseEnabled,
203-
},
204-
}}
205-
/>
158+
<>
159+
{disableEdit && (
160+
<Admonition
161+
type="default"
162+
className="m-0 py-2 rounded-none border-0 border-b [&>h5]:mb-0.5"
163+
title="This snippet has been shared to the project and is only editable by the owner who created this snippet"
164+
description='You may duplicate this snippet into a personal copy by right clicking on the snippet and selecting "Duplicate personal copy"'
165+
/>
166+
)}
167+
<Editor
168+
className={cn(className, 'monaco-editor')}
169+
theme={'supabase'}
170+
onMount={handleEditorOnMount}
171+
onChange={handleEditorChange}
172+
defaultLanguage="pgsql"
173+
defaultValue={snippet?.snippet.content.sql}
174+
path={id}
175+
options={{
176+
tabSize: 2,
177+
fontSize: 13,
178+
readOnly: disableEdit,
179+
minimap: { enabled: false },
180+
wordWrap: 'on',
181+
// [Joshen] Commenting the following out as it causes the autocomplete suggestion popover
182+
// to be positioned wrongly somehow. I'm not sure if this affects anything though, but leaving
183+
// comment just in case anyone might be wondering. Relevant issues:
184+
// - https://github.com/microsoft/monaco-editor/issues/2229
185+
// - https://github.com/microsoft/monaco-editor/issues/2503
186+
// fixedOverflowWidgets: true,
187+
suggest: {
188+
showMethods: intellisenseEnabled,
189+
showFunctions: intellisenseEnabled,
190+
showConstructors: intellisenseEnabled,
191+
showDeprecated: intellisenseEnabled,
192+
showFields: intellisenseEnabled,
193+
showVariables: intellisenseEnabled,
194+
showClasses: intellisenseEnabled,
195+
showStructs: intellisenseEnabled,
196+
showInterfaces: intellisenseEnabled,
197+
showModules: intellisenseEnabled,
198+
showProperties: intellisenseEnabled,
199+
showEvents: intellisenseEnabled,
200+
showOperators: intellisenseEnabled,
201+
showUnits: intellisenseEnabled,
202+
showValues: intellisenseEnabled,
203+
showConstants: intellisenseEnabled,
204+
showEnums: intellisenseEnabled,
205+
showEnumMembers: intellisenseEnabled,
206+
showKeywords: intellisenseEnabled,
207+
showWords: intellisenseEnabled,
208+
showColors: intellisenseEnabled,
209+
showFiles: intellisenseEnabled,
210+
showReferences: intellisenseEnabled,
211+
showFolders: intellisenseEnabled,
212+
showTypeParameters: intellisenseEnabled,
213+
showIssues: intellisenseEnabled,
214+
showUsers: intellisenseEnabled,
215+
showSnippets: intellisenseEnabled,
216+
},
217+
}}
218+
/>
219+
</>
206220
)
207221
}
208222

apps/studio/state/sql-editor-v2.ts

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -462,22 +462,37 @@ if (typeof window !== 'undefined') {
462462
const folder = state.folders[id]
463463

464464
if (snippet) {
465-
debouncedUpdateSnippet(id, snippet.projectRef, {
466-
id,
467-
type: 'sql',
468-
name: snippet.snippet.name ?? 'Untitled',
469-
description: snippet.snippet.description ?? '',
470-
visibility: snippet.snippet.visibility ?? 'user',
471-
project_id: snippet.snippet.project_id ?? 0,
472-
owner_id: snippet.snippet.owner_id,
473-
folder_id: snippet.snippet.folder_id,
474-
content: {
475-
...snippet.snippet.content,
476-
content_id: id,
477-
favorite: snippet.snippet.favorite,
478-
},
479-
})
480-
sqlEditorState.needsSaving.delete(id)
465+
const {
466+
name,
467+
description,
468+
visibility,
469+
project_id,
470+
owner_id,
471+
folder_id,
472+
content,
473+
favorite,
474+
} = snippet.snippet
475+
476+
if (visibility === 'project' && !!folder_id) {
477+
toast.error('Shared snippet cannot be within a folder')
478+
} else {
479+
debouncedUpdateSnippet(id, snippet.projectRef, {
480+
id,
481+
type: 'sql',
482+
name: name ?? 'Untitled',
483+
description: description ?? '',
484+
visibility: visibility ?? 'user',
485+
project_id: project_id ?? 0,
486+
owner_id: owner_id,
487+
folder_id: folder_id,
488+
content: {
489+
...content,
490+
content_id: id,
491+
favorite: favorite,
492+
},
493+
})
494+
sqlEditorState.needsSaving.delete(id)
495+
}
481496
} else if (folder) {
482497
upsertFolder(id, folder.projectRef, folder.folder.name)
483498
sqlEditorState.needsSaving.delete(id)

0 commit comments

Comments
 (0)