Skip to content

Commit 6965800

Browse files
authored
Merge pull request #2884 from appwrite/fix-column-encryption-for-other-attributes
fix: column encryption support for other attributes
2 parents 260c6eb + 1649d9b commit 6965800

8 files changed

Lines changed: 169 additions & 15 deletions

File tree

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
Tooltip,
1616
Typography
1717
} from '@appwrite.io/pink-svelte';
18-
import { isRelationship, isSpatialType, isString } from '../rows/store';
18+
import { isRelationship, isSpatialType, isTextType } from '../rows/store';
1919
import {
2020
columns,
2121
type Columns,
@@ -443,7 +443,7 @@
443443
{/if}
444444
</Typography.Text>
445445

446-
{#if isString(column) && column.encrypt}
446+
{#if isTextType(column) && 'encrypt' in column && column.encrypt}
447447
<Tooltip portal>
448448
<Icon
449449
size="s"
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<script lang="ts">
2+
import { page } from '$app/state';
3+
import { isCloud } from '$lib/system';
4+
import { getChangePlanUrl } from '$lib/stores/billing';
5+
import { currentPlan } from '$lib/stores/organization';
6+
import {
7+
ActionMenu,
8+
Popover,
9+
Layout,
10+
Selector,
11+
Tag,
12+
Tooltip,
13+
Typography,
14+
Link
15+
} from '@appwrite.io/pink-svelte';
16+
17+
let {
18+
encrypt = $bindable(false),
19+
editing = false,
20+
disabled = false,
21+
id = 'encrypt'
22+
}: {
23+
encrypt?: boolean;
24+
editing?: boolean;
25+
disabled?: boolean;
26+
id?: string;
27+
} = $props();
28+
29+
const organizationId = page.data?.organization?.$id ?? page.data?.project?.teamId;
30+
const supportsEncryption = $derived(isCloud ? $currentPlan?.databasesAllowEncrypt : true);
31+
</script>
32+
33+
<Tooltip disabled={!(editing || disabled)} maxWidth="275px" placement="bottom-start">
34+
<div
35+
class="popover-holder"
36+
class:cursor-not-allowed={editing || disabled}
37+
class:disabled-checkbox={!supportsEncryption || editing || disabled}>
38+
<Layout.Stack inline gap="s" alignItems="flex-start" direction="row">
39+
<Popover let:toggle placement="bottom-start">
40+
<Selector.Checkbox
41+
size="s"
42+
{id}
43+
bind:checked={encrypt}
44+
disabled={!supportsEncryption || editing || disabled} />
45+
46+
<Layout.Stack gap="xxs" direction="column">
47+
<button
48+
type="button"
49+
disabled={editing || disabled}
50+
class:cursor-pointer={!(editing || disabled)}
51+
class:cursor-not-allowed={editing || disabled}
52+
onclick={(e) => {
53+
if (!supportsEncryption) {
54+
toggle(e);
55+
} else {
56+
encrypt = !encrypt;
57+
}
58+
}}>
59+
<Layout.Stack inline gap="xxs" direction="row" alignItems="center">
60+
<Typography.Text variant="m-500">Encrypted</Typography.Text>
61+
{#if !supportsEncryption}
62+
<Tag variant="default" size="xs">Pro</Tag>
63+
{/if}
64+
</Layout.Stack>
65+
</button>
66+
<Typography.Text color="--fgcolor-neutral-tertiary">
67+
Protect column against data leaks for best privacy compliance. Encrypted
68+
columns cannot be queried.
69+
</Typography.Text>
70+
</Layout.Stack>
71+
72+
<ActionMenu.Root width="180px" slot="tooltip">
73+
<Typography.Text variant="m-500">
74+
Available on Pro plan. <Link.Anchor href={getChangePlanUrl(organizationId)}
75+
>Upgrade</Link.Anchor>
76+
to enable encrypted columns.
77+
</Typography.Text>
78+
</ActionMenu.Root>
79+
</Popover>
80+
</Layout.Stack>
81+
</div>
82+
83+
<svelte:fragment slot="tooltip">
84+
Encryption can only be set when creating the column.
85+
</svelte:fragment>
86+
</Tooltip>
87+
88+
<style lang="scss">
89+
.popover-holder {
90+
& :global([role='tooltip']) {
91+
margin-top: 4px;
92+
left: 8rem !important;
93+
}
94+
95+
&.disabled-checkbox :global(button) {
96+
cursor: unset;
97+
}
98+
}
99+
100+
.cursor-pointer {
101+
cursor: pointer !important;
102+
}
103+
104+
.cursor-not-allowed {
105+
cursor: not-allowed;
106+
}
107+
</style>

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/longtext.svelte

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
key,
1818
required: data.required,
1919
xdefault: data.default,
20-
array: data.array
20+
array: data.array,
21+
encrypt: data.encrypt
2122
});
2223
}
2324
export async function updateLongtext(
@@ -42,17 +43,21 @@
4243
<script lang="ts">
4344
import { createConservative } from '$lib/helpers/stores';
4445
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
46+
import EncryptCheckbox from './encryptCheckbox.svelte';
4547
import { InputTextarea } from '$lib/elements/forms';
4648
import { Layout, Typography } from '@appwrite.io/pink-svelte';
4749
4850
export let data: Partial<Models.ColumnLongtext> = {
4951
required: false,
50-
array: false
52+
array: false,
53+
encrypt: false
5154
};
5255
5356
export let editing = false;
5457
export let disabled = false;
5558
59+
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
60+
5661
let savedDefault = data.default;
5762
5863
function handleDefaultState(hideDefault: boolean) {
@@ -97,3 +102,7 @@
97102
{disabled}
98103
bind:array={data.array}
99104
bind:required={data.required} />
105+
106+
<Layout.Stack gap="xs" direction="column">
107+
<EncryptCheckbox id="encrypt-longtext" bind:encrypt={data.encrypt} {editing} {disabled} />
108+
</Layout.Stack>

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/mediumtext.svelte

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
key,
1818
required: data.required,
1919
xdefault: data.default,
20-
array: data.array
20+
array: data.array,
21+
encrypt: data.encrypt
2122
});
2223
}
2324
export async function updateMediumtext(
@@ -42,17 +43,21 @@
4243
<script lang="ts">
4344
import { createConservative } from '$lib/helpers/stores';
4445
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
46+
import EncryptCheckbox from './encryptCheckbox.svelte';
4547
import { InputTextarea } from '$lib/elements/forms';
4648
import { Layout, Typography } from '@appwrite.io/pink-svelte';
4749
4850
export let data: Partial<Models.ColumnMediumtext> = {
4951
required: false,
50-
array: false
52+
array: false,
53+
encrypt: false
5154
};
5255
5356
export let editing = false;
5457
export let disabled = false;
5558
59+
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
60+
5661
let savedDefault = data.default;
5762
5863
function handleDefaultState(hideDefault: boolean) {
@@ -97,3 +102,7 @@
97102
{disabled}
98103
bind:array={data.array}
99104
bind:required={data.required} />
105+
106+
<Layout.Stack gap="xs" direction="column">
107+
<EncryptCheckbox id="encrypt-mediumtext" bind:encrypt={data.encrypt} {editing} {disabled} />
108+
</Layout.Stack>

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/text.svelte

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
key,
1616
required: data.required,
1717
xdefault: data.default,
18-
array: data.array
18+
array: data.array,
19+
encrypt: data.encrypt
1920
});
2021
}
2122
export async function updateText(
@@ -38,17 +39,21 @@
3839
<script lang="ts">
3940
import { createConservative } from '$lib/helpers/stores';
4041
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
42+
import EncryptCheckbox from './encryptCheckbox.svelte';
4143
import { InputTextarea } from '$lib/elements/forms';
4244
import { Layout, Typography } from '@appwrite.io/pink-svelte';
4345
4446
export let data: Partial<Models.ColumnText> = {
4547
required: false,
46-
array: false
48+
array: false,
49+
encrypt: false
4750
};
4851
4952
export let editing = false;
5053
export let disabled = false;
5154
55+
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
56+
5257
let savedDefault = data.default;
5358
5459
function handleDefaultState(hideDefault: boolean) {
@@ -93,3 +98,7 @@
9398
{disabled}
9499
bind:array={data.array}
95100
bind:required={data.required} />
101+
102+
<Layout.Stack gap="xs" direction="column">
103+
<EncryptCheckbox id="encrypt-text" bind:encrypt={data.encrypt} {editing} {disabled} />
104+
</Layout.Stack>

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/varchar.svelte

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
size: data.size,
1717
required: data.required,
1818
xdefault: data.default,
19-
array: data.array
19+
array: data.array,
20+
encrypt: data.encrypt
2021
});
2122
}
2223
export async function updateVarchar(
@@ -45,16 +46,20 @@
4546
import { ProgressBar } from '$lib/components';
4647
import { Layout, Typography, Tooltip, Icon } from '@appwrite.io/pink-svelte';
4748
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
49+
import EncryptCheckbox from './encryptCheckbox.svelte';
4850
4951
export let data: Partial<Models.ColumnVarchar> = {
5052
required: false,
5153
size: 255,
52-
array: false
54+
array: false,
55+
encrypt: false
5356
};
5457
5558
export let editing = false;
5659
export let disabled = false;
5760
61+
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
62+
5863
// Local size for reactivity
5964
let size = data.size ?? 255;
6065
$: data.size = size;
@@ -118,6 +123,10 @@
118123
$: listen(data);
119124
120125
$: handleDefaultState($required || $array);
126+
127+
$: if (data.encrypt && size < 150) {
128+
size = 150;
129+
}
121130
</script>
122131

123132
<InputNumber
@@ -127,8 +136,11 @@
127136
{disabled}
128137
placeholder="Enter size"
129138
bind:value={size}
130-
min={1}
131-
max={16383} />
139+
min={data.encrypt ? 150 : 1}
140+
max={16383}
141+
helper={data.encrypt
142+
? 'Encrypted varchar columns require a minimum size of 150.'
143+
: undefined} />
132144

133145
{#if !editing}
134146
<Layout.Stack gap="xs">
@@ -173,3 +185,7 @@
173185
{disabled}
174186
bind:array={data.array}
175187
bind:required={data.required} />
188+
189+
<Layout.Stack gap="xs" direction="column">
190+
<EncryptCheckbox id="encrypt-varchar" bind:encrypt={data.encrypt} {editing} {disabled} />
191+
</Layout.Stack>

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
required: column?.required ?? false,
4848
array: column?.array ?? false,
4949
default: column?.default ?? null,
50+
encrypt: (column as { encrypt?: boolean })?.encrypt ?? false,
5051
...column
5152
} as Partial<Columns>);
5253
@@ -60,7 +61,8 @@
6061
data = {
6162
required: false,
6263
array: false,
63-
default: null
64+
default: null,
65+
encrypt: false
6466
};
6567
6668
/* default to text */

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
isRelationship,
1818
isRelationshipToMany,
1919
isSpatialType,
20-
isString
20+
isTextType
2121
} from './rows/store';
2222
import {
2323
columns,
@@ -1072,7 +1072,9 @@
10721072
{@const isEmptyArray = formatted === 'Empty'}
10731073
{@const isDatetimeAttribute = rowColumn.type === 'datetime'}
10741074
{@const isEncryptedAttribute =
1075-
isString(rowColumn) && rowColumn.encrypt}
1075+
isTextType(rowColumn) &&
1076+
'encrypt' in rowColumn &&
1077+
rowColumn.encrypt}
10761078
{#if isDatetimeAttribute}
10771079
<DualTimeView time={value}>
10781080
<span slot="title">Timestamp</span>

0 commit comments

Comments
 (0)