Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 0 additions & 64 deletions .github/dependabot.yml

This file was deleted.

25 changes: 25 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Security Policy

## Supported Versions

Currently supported, maintained and updated versions:

| Version | Supported | Support Status |
| ------- | ------------------ | ------------------------------------- |
| 4.x | :white_check_mark: | Active Development & Security Updates |
| < 4.0 | :x: | End of Life (no security updates) |

## Security Updates

We take security seriously. Security updates are released as soon as possible after a vulnerability is discovered and verified.

## Reporting a Vulnerability

If you discover a security vulnerability, please follow these steps:

1. **DO NOT** disclose the vulnerability publicly.
2. Send a detailed report to: `cto@0.email`.
3. Include in your report:
- A description of the vulnerability
- Steps to reproduce the issue
- Potential impact
111 changes: 50 additions & 61 deletions apps/mail/app/(routes)/settings/general/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ import {
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { useForm, type ControllerRenderProps } from 'react-hook-form';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { SettingsCard } from '@/components/settings/settings-card';
import { Globe, Clock, XIcon, Mail, InfoIcon } from 'lucide-react';
import { useEmailAliases } from '@/hooks/use-email-aliases';
import { useState, useEffect, useMemo, memo } from 'react';
import { userSettingsSchema } from '@zero/server/schemas';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Globe, Clock, XIcon, Mail } from 'lucide-react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useTranslations, useLocale } from 'use-intl';
import { useTRPC } from '@/providers/query-provider';
Expand Down Expand Up @@ -200,7 +201,7 @@ export default function GeneralPage() {
>
<Form {...form}>
<form id="general-form" onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<div className="flex w-full items-center gap-5">
<div className="flex w-full items-center gap-4">
<FormField
control={form.control}
name="language"
Expand Down Expand Up @@ -235,70 +236,58 @@ export default function GeneralPage() {
</FormItem>
)}
/>
</div>
{aliases && aliases.length > 0 && (
<FormField
control={form.control}
name="defaultEmailAlias"
render={({ field }) => (
<FormItem>
<FormLabel>{t('pages.settings.general.defaultEmailAlias')}</FormLabel>
<Select onValueChange={field.onChange} value={field.value || ''}>
<FormControl>
<SelectTrigger className="w-[300px] justify-start">
<Mail className="mr-2 h-4 w-4" />
<SelectValue
placeholder={t('pages.settings.general.selectDefaultEmail')}
/>
</SelectTrigger>
</FormControl>
<SelectContent>
{aliases.map((alias) => (
<SelectItem key={alias.email} value={alias.email}>
<div className="flex flex-row items-center gap-1">
<span className="text-sm">
{alias.name ? `${alias.name} <${alias.email}>` : alias.email}
</span>
{alias.primary && (
<span className="text-muted-foreground text-xs">(Primary)</span>
)}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
<FormDescription>
{t('pages.settings.general.defaultEmailDescription')}
</FormDescription>
</FormItem>
)}
/>
)}
<FormField
control={form.control}
name="customPrompt"
render={({ field }) => (
<FormItem>
<FormLabel>{t('pages.settings.general.customPrompt')}</FormLabel>
<FormControl>
<Textarea
placeholder={t('pages.settings.general.customPromptPlaceholder')}
className="min-h-[150px]"
maxLength={3000}
{...field}
/>
</FormControl>
<FormDescription>
{t('pages.settings.general.customPromptDescription')}
</FormDescription>
</FormItem>
{aliases && aliases.length > 0 && (
<FormField
control={form.control}
name="defaultEmailAlias"
render={({ field }) => (
<FormItem>
<FormLabel className="flex items-center gap-1">
{t('pages.settings.general.defaultEmailAlias')}{' '}
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-4 w-4" />
</TooltipTrigger>
<TooltipContent>
{t('pages.settings.general.defaultEmailDescription')}
</TooltipContent>
</Tooltip>
</FormLabel>
<Select onValueChange={field.onChange} value={field.value || ''}>
<FormControl>
<SelectTrigger className="w-[300px] justify-start">
<Mail className="mr-2 h-4 w-4" />
<SelectValue
placeholder={t('pages.settings.general.selectDefaultEmail')}
/>
</SelectTrigger>
</FormControl>
<SelectContent>
{aliases.map((alias) => (
<SelectItem key={alias.email} value={alias.email}>
<div className="flex flex-row items-center gap-1">
<span className="text-sm">
{alias.name ? `${alias.name} <${alias.email}>` : alias.email}
</span>
{alias.primary && (
<span className="text-muted-foreground text-xs">(Primary)</span>
)}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
)}
/>
)}
/>
</div>

<FormField
control={form.control}
name="zeroSignature"
render={({ field }) => (
<FormItem className="flex max-w-xl flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
<FormItem className="flex max-w-xl flex-row items-center justify-between rounded-lg border px-4 py-2">
<div className="space-y-0.5">
<FormLabel>{t('pages.settings.general.zeroSignature')}</FormLabel>
<FormDescription>
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/lib/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export const userSettingsSchema = z.object({
timezone: z.string(),
dynamicContent: z.boolean().optional(),
externalImages: z.boolean(),
customPrompt: z.string(),
customPrompt: z.string().default(''),
isOnboarded: z.boolean().optional(),
trustedSenders: z.string().array().optional(),
colorTheme: z.enum(['light', 'dark', 'system']).default('system'),
Expand Down