mirror of
https://github.com/lone-cloud/prism
synced 2026-06-04 04:04:44 -07:00
new endpoint to mark emails as read
This commit is contained in:
parent
40630a6dee
commit
2716fa1b57
6 changed files with 82 additions and 33 deletions
24
bun.lock
24
bun.lock
|
|
@ -6,12 +6,12 @@
|
|||
"name": "sup",
|
||||
"dependencies": {
|
||||
"chalk": "5.6.2",
|
||||
"hono": "4.11.5",
|
||||
"hono": "4.11.7",
|
||||
"hono-rate-limiter": "0.5.3",
|
||||
"imap": "0.8.19",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.12",
|
||||
"@biomejs/biome": "2.3.13",
|
||||
"@types/bun": "1.3.6",
|
||||
"@types/imap": "0.8.43",
|
||||
"typescript": "5.9.3",
|
||||
|
|
@ -19,23 +19,23 @@
|
|||
},
|
||||
},
|
||||
"packages": {
|
||||
"@biomejs/biome": ["@biomejs/biome@2.3.12", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.12", "@biomejs/cli-darwin-x64": "2.3.12", "@biomejs/cli-linux-arm64": "2.3.12", "@biomejs/cli-linux-arm64-musl": "2.3.12", "@biomejs/cli-linux-x64": "2.3.12", "@biomejs/cli-linux-x64-musl": "2.3.12", "@biomejs/cli-win32-arm64": "2.3.12", "@biomejs/cli-win32-x64": "2.3.12" }, "bin": { "biome": "bin/biome" } }, "sha512-AR7h4aSlAvXj7TAajW/V12BOw2EiS0AqZWV5dGozf4nlLoUF/ifvD0+YgKSskT0ylA6dY1A8AwgP8kZ6yaCQnA=="],
|
||||
"@biomejs/biome": ["@biomejs/biome@2.3.13", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.13", "@biomejs/cli-darwin-x64": "2.3.13", "@biomejs/cli-linux-arm64": "2.3.13", "@biomejs/cli-linux-arm64-musl": "2.3.13", "@biomejs/cli-linux-x64": "2.3.13", "@biomejs/cli-linux-x64-musl": "2.3.13", "@biomejs/cli-win32-arm64": "2.3.13", "@biomejs/cli-win32-x64": "2.3.13" }, "bin": { "biome": "bin/biome" } }, "sha512-Fw7UsV0UAtWIBIm0M7g5CRerpu1eKyKAXIazzxhbXYUyMkwNrkX/KLkGI7b+uVDQ5cLUMfOC9vR60q9IDYDstA=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cO6fn+KiMBemva6EARDLQBxeyvLzgidaFRJi8G7OeRqz54kWK0E+uSjgFaiHlc3DZYoa0+1UFE8mDxozpc9ieg=="],
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0OCwP0/BoKzyJHnFdaTk/i7hIP9JHH9oJJq6hrSCPmJPo8JWcJhprK4gQlhFzrwdTBAW4Bjt/RmCf3ZZe59gwQ=="],
|
||||
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-/fiF/qmudKwSdvmSrSe/gOTkW77mHHkH8Iy7YC2rmpLuk27kbaUOPa7kPiH5l+3lJzTUfU/t6x1OuIq/7SGtxg=="],
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-AGr8OoemT/ejynbIu56qeil2+F2WLkIjn2d8jGK1JkchxnMUhYOfnqc9sVzcRxpG9Ycvw4weQ5sprRvtb7Yhcw=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-nbOsuQROa3DLla5vvsTZg+T5WVPGi9/vYxETm9BOuLHBJN3oWQIg3MIkE2OfL18df1ZtNkqXkH6Yg9mdTPem7A=="],
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-xvOiFkrDNu607MPMBUQ6huHmBG1PZLOrqhtK6pXJW3GjfVqJg0Z/qpTdhXfcqWdSZHcT+Nct2fOgewZvytESkw=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-aqkeSf7IH+wkzFpKeDVPSXy9uDjxtLpYA6yzkYsY+tVjwFFirSuajHDI3ul8en90XNs1NA0n8kgBrjwRi5JeyA=="],
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-TUdDCSY+Eo/EHjhJz7P2GnWwfqet+lFxBZzGHldrvULr59AgahamLs/N85SC4+bdF86EhqDuuw9rYLvLFWWlXA=="],
|
||||
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.12", "", { "os": "linux", "cpu": "x64" }, "sha512-CQtqrJ+qEEI8tgRSTjjzk6wJAwfH3wQlkIGsM5dlecfRZaoT+XCms/mf7G4kWNexrke6mnkRzNy6w8ebV177ow=="],
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.13", "", { "os": "linux", "cpu": "x64" }, "sha512-s+YsZlgiXNq8XkgHs6xdvKDFOj/bwTEevqEY6rC2I3cBHbxXYU1LOZstH3Ffw9hE5tE1sqT7U23C00MzkXztMw=="],
|
||||
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.12", "", { "os": "linux", "cpu": "x64" }, "sha512-kVGWtupRRsOjvw47YFkk5mLiAdpCPMWBo1jOwAzh+juDpUb2sWarIp+iq+CPL1Wt0LLZnYtP7hH5kD6fskcxmg=="],
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.13", "", { "os": "linux", "cpu": "x64" }, "sha512-0bdwFVSbbM//Sds6OjtnmQGp4eUjOTt6kHvR/1P0ieR9GcTUAlPNvPC3DiavTqq302W34Ae2T6u5VVNGuQtGlQ=="],
|
||||
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-Re4I7UnOoyE4kHMqpgtG6UvSBGBbbtvsOvBROgCCoH7EgANN6plSQhvo2W7OCITvTp7gD6oZOyZy72lUdXjqZg=="],
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-QweDxY89fq0VvrxME+wS/BXKmqMrOTZlN9SqQ79kQSIc3FrEwvW/PvUegQF6XIVaekncDykB5dzPqjbwSKs9DA=="],
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.12", "", { "os": "win32", "cpu": "x64" }, "sha512-qqGVWqNNek0KikwPZlOIoxtXgsNGsX+rgdEzgw82Re8nF02W+E2WokaQhpF5TdBh/D/RQ3TLppH+otp6ztN0lw=="],
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.13", "", { "os": "win32", "cpu": "x64" }, "sha512-trDw2ogdM2lyav9WFQsdsfdVy1dvZALymRpgmWsvSez0BJzBjulhOT/t+wyKeh3pZWvwP3VMs1SoOKwO3wecMQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
||||
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||
|
||||
"hono": ["hono@4.11.5", "", {}, "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g=="],
|
||||
"hono": ["hono@4.11.7", "", {}, "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw=="],
|
||||
|
||||
"hono-rate-limiter": ["hono-rate-limiter@0.5.3", "", { "peerDependencies": { "hono": "^4.10.8", "unstorage": "^1.17.3" }, "optionalPeers": ["unstorage"] }, "sha512-M0DxbVMpPELEzLi0AJg1XyBHLGJXz7GySjsPoK+gc5YeeBsdGDGe+2RvVuCAv8ydINiwlbxqYMNxUEyYfRji/A=="],
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sup",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"description": "Privacy-preserving push notifications using Signal as transport",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
|
@ -23,12 +23,12 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"chalk": "5.6.2",
|
||||
"hono": "4.11.5",
|
||||
"hono": "4.11.7",
|
||||
"hono-rate-limiter": "0.5.3",
|
||||
"imap": "0.8.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.12",
|
||||
"@biomejs/biome": "2.3.13",
|
||||
"@types/bun": "1.3.6",
|
||||
"@types/imap": "0.8.43",
|
||||
"typescript": "5.9.3"
|
||||
|
|
|
|||
|
|
@ -27,28 +27,11 @@ try {
|
|||
Pull the latest version:
|
||||
\`\`\`bash
|
||||
docker pull ghcr.io/lone-cloud/sup:${version}
|
||||
\`\`\`
|
||||
|
||||
Or use in your \`docker-compose.yml\`:
|
||||
\`\`\`yaml
|
||||
services:
|
||||
server:
|
||||
image: ghcr.io/lone-cloud/sup:${version}
|
||||
\`\`\`
|
||||
|
||||
### Architectures
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
|
||||
### Changes
|
||||
See commit history for details." --generate-notes`;
|
||||
\`\`\`" --generate-notes`;
|
||||
|
||||
console.log(`
|
||||
✨ Release ${version} complete!
|
||||
|
||||
GitHub release: https://github.com/lone-cloud/sup/releases/tag/${version}
|
||||
GitHub Actions: https://github.com/lone-cloud/sup/actions
|
||||
|
||||
Once CI completes, images will be available:
|
||||
docker pull ghcr.io/lone-cloud/sup:${version}
|
||||
`);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { PUBLIC_DIR } from '@/constants/paths';
|
|||
import { cleanupDaemon, initSignal } from '@/modules/signal';
|
||||
import { admin } from '@/routes/admin';
|
||||
import { ntfy } from '@/routes/ntfy';
|
||||
import { protonMail } from '@/routes/proton-mail';
|
||||
import { getLanIP, isLocalIP } from '@/utils/auth';
|
||||
import { formatToCspString } from '@/utils/format';
|
||||
import { logError, logInfo, logVerbose, logWarn } from '@/utils/log';
|
||||
|
|
@ -80,6 +81,7 @@ app.use('*', serveStatic({ root: PUBLIC_DIR }));
|
|||
|
||||
app.route('/', ntfy);
|
||||
app.route('/', admin);
|
||||
app.route('/', protonMail);
|
||||
|
||||
app.notFound((c) => c.text('Not Found', 404));
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ let imapConnected = false;
|
|||
let monitorStartTime = 0;
|
||||
let reconnectAttempts = 0;
|
||||
const MAX_RECONNECT_DELAY = 300000; // 5 minutes
|
||||
let imapInstance: Imap | null = null;
|
||||
|
||||
export const isImapConnected = () => imapConnected;
|
||||
|
||||
|
|
@ -167,4 +168,28 @@ export async function startProtonMonitor() {
|
|||
process.on('SIGTERM', () => imap.end());
|
||||
|
||||
process.on('SIGINT', () => imap.end());
|
||||
|
||||
imapInstance = imap;
|
||||
}
|
||||
|
||||
export async function markEmailAsRead(uid: number) {
|
||||
if (!imapInstance || !imapConnected) {
|
||||
return { success: false, error: 'IMAP not connected' };
|
||||
}
|
||||
|
||||
return new Promise<{ success: boolean; error?: string }>((resolve) => {
|
||||
try {
|
||||
imapInstance?.addFlags(uid, '\\Seen', (err) => {
|
||||
if (err) {
|
||||
logError('Failed to mark email as read:', err);
|
||||
resolve({ success: false, error: err.message });
|
||||
} else {
|
||||
resolve({ success: true });
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
resolve({ success: false, error: errorMessage });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
39
server/routes/proton-mail.ts
Normal file
39
server/routes/proton-mail.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { Hono } from 'hono';
|
||||
import { basicAuth } from 'hono/basic-auth';
|
||||
import { markEmailAsRead } from '@/modules/proton-mail';
|
||||
import { verifyApiKey } from '@/utils/auth';
|
||||
import { logError, logVerbose } from '@/utils/log';
|
||||
|
||||
export const protonMail = new Hono();
|
||||
|
||||
protonMail.use(
|
||||
'*',
|
||||
basicAuth({
|
||||
verifyUser: (_, password, c) => verifyApiKey(password, c),
|
||||
realm: 'SUP Proton Mail - Username: any, Password: API_KEY',
|
||||
}),
|
||||
);
|
||||
|
||||
protonMail.post('/api/proton-mail/mark-read', async (c) => {
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
const { uid } = body;
|
||||
|
||||
if (!uid || typeof uid !== 'number') {
|
||||
return c.json({ error: 'uid (number) is required' }, 400);
|
||||
}
|
||||
|
||||
const result = await markEmailAsRead(uid);
|
||||
|
||||
if (!result.success) {
|
||||
return c.json({ error: result.error }, 500);
|
||||
}
|
||||
|
||||
logVerbose(`Marked email as read: UID ${uid}`);
|
||||
|
||||
return c.json({ success: true });
|
||||
} catch (error) {
|
||||
logError('Failed to mark email as read:', error);
|
||||
return c.json({ error: 'Internal server error' }, 500);
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue