mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59b2b53837 | ||
|
|
e99487eed9 | ||
|
|
8d4e5d2d4e | ||
|
|
daea3e64e4 |
@@ -18,6 +18,10 @@
|
||||
> [!WARNING]
|
||||
> Zerobyte is still in version 0.x.x and is subject to major changes from version to version. I am developing the core features and collecting feedbacks. Expect bugs! Please open issues or feature requests
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.buymeacoffee.com/nicotsx" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
||||
</p>
|
||||
|
||||
## Intro
|
||||
|
||||
Zerobyte is a backup automation tool that helps you save your data across multiple storage backends. Built on top of Restic, it provides an modern web interface to schedule, manage, and monitor encrypted backups of your remote storage.
|
||||
|
||||
@@ -1859,13 +1859,15 @@ export type GetScheduleNotificationsResponses = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -1873,6 +1875,7 @@ export type GetScheduleNotificationsResponses = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -1940,13 +1943,15 @@ export type UpdateScheduleNotificationsResponses = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -1954,6 +1959,7 @@ export type UpdateScheduleNotificationsResponses = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -2010,13 +2016,15 @@ export type ListNotificationDestinationsResponses = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -2024,6 +2032,7 @@ export type ListNotificationDestinationsResponses = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -2064,13 +2073,15 @@ export type CreateNotificationDestinationData = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -2078,6 +2089,7 @@ export type CreateNotificationDestinationData = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -2117,13 +2129,15 @@ export type CreateNotificationDestinationResponses = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -2131,6 +2145,7 @@ export type CreateNotificationDestinationResponses = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -2217,13 +2232,15 @@ export type GetNotificationDestinationResponses = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -2231,6 +2248,7 @@ export type GetNotificationDestinationResponses = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -2271,13 +2289,15 @@ export type UpdateNotificationDestinationData = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -2285,6 +2305,7 @@ export type UpdateNotificationDestinationData = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
@@ -2334,13 +2355,15 @@ export type UpdateNotificationDestinationResponses = {
|
||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||
topic: string;
|
||||
type: 'ntfy';
|
||||
password?: string;
|
||||
serverUrl?: string;
|
||||
token?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
priority: number;
|
||||
serverUrl: string;
|
||||
token: string;
|
||||
type: 'gotify';
|
||||
path?: string;
|
||||
} | {
|
||||
shoutrrrUrl: string;
|
||||
type: 'custom';
|
||||
@@ -2348,6 +2371,7 @@ export type UpdateNotificationDestinationResponses = {
|
||||
type: 'discord';
|
||||
webhookUrl: string;
|
||||
avatarUrl?: string;
|
||||
threadId?: string;
|
||||
username?: string;
|
||||
} | {
|
||||
type: 'slack';
|
||||
|
||||
@@ -370,6 +370,22 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="threadId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Thread ID (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
ID of the thread to post messages in. Leave empty to post in the main channel.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -423,6 +439,20 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="path"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Path (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="/custom/path" />
|
||||
</FormControl>
|
||||
<FormDescription>Custom path on the Gotify server, if applicable.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -458,14 +488,28 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="token"
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Access Token (Optional)</FormLabel>
|
||||
<FormLabel>Username (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="username" />
|
||||
</FormControl>
|
||||
<FormDescription>Username for server authentication, if required.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="password" placeholder="••••••••" />
|
||||
</FormControl>
|
||||
<FormDescription>Required if the topic is protected.</FormDescription>
|
||||
<FormDescription>Password for server authentication, if required.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
@@ -36,12 +36,14 @@ export const discordNotificationConfigSchema = type({
|
||||
webhookUrl: "string",
|
||||
username: "string?",
|
||||
avatarUrl: "string?",
|
||||
threadId: "string?",
|
||||
});
|
||||
|
||||
export const gotifyNotificationConfigSchema = type({
|
||||
type: "'gotify'",
|
||||
serverUrl: "string",
|
||||
token: "string",
|
||||
path: "string?",
|
||||
priority: "0 <= number <= 10",
|
||||
});
|
||||
|
||||
@@ -49,8 +51,9 @@ export const ntfyNotificationConfigSchema = type({
|
||||
type: "'ntfy'",
|
||||
serverUrl: "string?",
|
||||
topic: "string",
|
||||
token: "string?",
|
||||
priority: "'max' | 'high' | 'default' | 'low' | 'min'",
|
||||
username: "string?",
|
||||
password: "string?",
|
||||
});
|
||||
|
||||
export const pushoverNotificationConfigSchema = type({
|
||||
|
||||
@@ -17,7 +17,10 @@ export function buildDiscordShoutrrrUrl(config: Extract<NotificationConfig, { ty
|
||||
params.append("username", config.username);
|
||||
}
|
||||
if (config.avatarUrl) {
|
||||
params.append("avatar_url", config.avatarUrl);
|
||||
params.append("avatarurl", config.avatarUrl);
|
||||
}
|
||||
if (config.threadId) {
|
||||
params.append("thread_id", config.threadId);
|
||||
}
|
||||
|
||||
if (params.toString()) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { NotificationConfig } from "~/schemas/notifications";
|
||||
|
||||
export function buildEmailShoutrrrUrl(config: Extract<NotificationConfig, { type: "email" }>): string {
|
||||
const protocol = config.useTLS ? "smtps" : "smtp";
|
||||
const auth = `${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}`;
|
||||
const host = `${config.smtpHost}:${config.smtpPort}`;
|
||||
const toRecipients = config.to.map((email) => encodeURIComponent(email)).join(",");
|
||||
const useStartTLS = config.useTLS ? "yes" : "no";
|
||||
|
||||
return `${protocol}://${auth}@${host}/?from=${encodeURIComponent(config.from)}&to=${toRecipients}`;
|
||||
return `smtp://${auth}@${host}/?from=${encodeURIComponent(config.from)}&to=${toRecipients}&starttls=${useStartTLS}`;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@ export function buildGotifyShoutrrrUrl(config: Extract<NotificationConfig, { typ
|
||||
const url = new URL(config.serverUrl);
|
||||
const hostname = url.hostname;
|
||||
const port = url.port ? `:${url.port}` : "";
|
||||
const path = config.path ? `/${config.path.replace(/^\/+|\/+$/g, "")}` : "";
|
||||
|
||||
let shoutrrrUrl = `gotify://${hostname}${port}/${config.token}`;
|
||||
let shoutrrrUrl = `gotify://${hostname}${port}${path}/${config.token}`;
|
||||
|
||||
if (config.priority !== undefined) {
|
||||
shoutrrrUrl += `?priority=${config.priority}`;
|
||||
|
||||
@@ -3,19 +3,26 @@ import type { NotificationConfig } from "~/schemas/notifications";
|
||||
export function buildNtfyShoutrrrUrl(config: Extract<NotificationConfig, { type: "ntfy" }>): string {
|
||||
let shoutrrrUrl: string;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
|
||||
const auth =
|
||||
config.username && config.password
|
||||
? `${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}@`
|
||||
: "";
|
||||
|
||||
if (config.serverUrl) {
|
||||
const url = new URL(config.serverUrl);
|
||||
const hostname = url.hostname;
|
||||
const port = url.port ? `:${url.port}` : "";
|
||||
shoutrrrUrl = `ntfy://${hostname}${port}/${config.topic}`;
|
||||
const scheme = url.protocol === "https:" ? "https" : "http";
|
||||
|
||||
params.append("scheme", scheme);
|
||||
|
||||
shoutrrrUrl = `ntfy://${auth}${hostname}${port}/${config.topic}`;
|
||||
} else {
|
||||
shoutrrrUrl = `ntfy://ntfy.sh/${config.topic}`;
|
||||
shoutrrrUrl = `ntfy://${auth}ntfy.sh/${config.topic}`;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (config.token) {
|
||||
params.append("token", config.token);
|
||||
}
|
||||
if (config.priority) {
|
||||
params.append("priority", config.priority);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export function buildSlackShoutrrrUrl(config: Extract<NotificationConfig, { type
|
||||
params.append("username", config.username);
|
||||
}
|
||||
if (config.iconEmoji) {
|
||||
params.append("icon", config.iconEmoji);
|
||||
params.append("icon_emoji", config.iconEmoji);
|
||||
}
|
||||
|
||||
if (params.toString()) {
|
||||
|
||||
@@ -58,7 +58,7 @@ async function encryptSensitiveFields(config: NotificationConfig): Promise<Notif
|
||||
case "ntfy":
|
||||
return {
|
||||
...config,
|
||||
token: config.token ? await cryptoUtils.encrypt(config.token) : undefined,
|
||||
password: config.password ? await cryptoUtils.encrypt(config.password) : undefined,
|
||||
};
|
||||
case "pushover":
|
||||
return {
|
||||
@@ -100,7 +100,7 @@ async function decryptSensitiveFields(config: NotificationConfig): Promise<Notif
|
||||
case "ntfy":
|
||||
return {
|
||||
...config,
|
||||
token: config.token ? await cryptoUtils.decrypt(config.token) : undefined,
|
||||
password: config.password ? await cryptoUtils.decrypt(config.password) : undefined,
|
||||
};
|
||||
case "pushover":
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user