temp commit
This commit is contained in:
parent
504c3c055b
commit
be4aaf0dd4
|
@ -37,5 +37,6 @@ Check out our [Next.js deployment documentation](https://nextjs.org/docs/deploym
|
|||
|
||||
### notes to add later
|
||||
```sql
|
||||
CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT NOT NULL, alias TEXT NOT NULL, pending INTEGER DEFAULT 0);
|
||||
CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT NOT NULL, alias TEXT NOT NULL, pending INTEGER DEFAULT 0, temporary INTEGER DEFAULT 0);
|
||||
CREATE TABLE temp_alias_requests (key TEXT PRIMARY KEY, address TEXT NOT NULL, alias TEXT NOT NULL, expires INTEGER NOT NULL);
|
||||
```
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"lucide-react": "^0.311.0",
|
||||
"next": "14.0.4",
|
||||
"next-auth": "^4.24.5",
|
||||
"random-words": "^2.0.0",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"sqlite3": "^5.1.7"
|
||||
|
|
|
@ -29,6 +29,9 @@ dependencies:
|
|||
next-auth:
|
||||
specifier: ^4.24.5
|
||||
version: 4.24.5(next@14.0.4)(react-dom@18.2.0)(react@18.2.0)
|
||||
random-words:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
react:
|
||||
specifier: ^18
|
||||
version: 18.2.0
|
||||
|
@ -4029,6 +4032,12 @@ packages:
|
|||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
dev: true
|
||||
|
||||
/random-words@2.0.0:
|
||||
resolution: {integrity: sha512-uqpnDqFnYrZajgmvgjmBrSZL2V1UA/9bNPGrilo12CmBeBszoff/avElutUlwWxG12gvmCk/8dUhvHefYxzYjw==}
|
||||
dependencies:
|
||||
seedrandom: 3.0.5
|
||||
dev: false
|
||||
|
||||
/rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
@ -4244,6 +4253,10 @@ packages:
|
|||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/seedrandom@3.0.5:
|
||||
resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
|
||||
dev: false
|
||||
|
||||
/semver@6.3.1:
|
||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||
hasBin: true
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import ConnectionDetailsCard from "@/lib/components/ui/user/ConnectionDetailsCard";
|
||||
import OwnAliasesCard from "@/lib/components/ui/user/OwnAliasesCard";
|
||||
import OwnCredentialsCard from "@/lib/components/ui/user/OwnCredentialsCard";
|
||||
import TempAliasesCard from "@/lib/components/ui/user/TempAliasesCard";
|
||||
import useWindowDimensions from "@/lib/hooks/useWindowDimensions";
|
||||
import { Grid, Heading } from "@radix-ui/themes";
|
||||
|
||||
|
@ -14,10 +15,11 @@ export default function SelfService() {
|
|||
<>
|
||||
<Heading className="pb-4">Account settings</Heading>
|
||||
|
||||
<Grid display="inline-grid" columns={mobileUi ? "1" : "3"} gap="4" width={mobileUi ? "100%" : "auto"}>
|
||||
<Grid display="inline-grid" columns={mobileUi ? "1" : "4"} gap="4" width={mobileUi ? "100%" : "auto"}>
|
||||
<OwnCredentialsCard />
|
||||
<ConnectionDetailsCard />
|
||||
<OwnAliasesCard />
|
||||
<TempAliasesCard />
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
"use server";
|
||||
|
||||
import { getServerSession } from "next-auth";
|
||||
import { AliasEntry, approveAliasEntry, createAliasEntry, createUserEntry, database, deleteAliasEntry, getAlias, getAllAliases, getUserAliases, setUserPassword } from "./db";
|
||||
import { aliasesNeedApproval, isAdmin } from "./util";
|
||||
import { AuditLog, auditLog } from "./audit";
|
||||
import crypto from "crypto";
|
||||
import fs from "fs/promises";
|
||||
import { getServerSession } from "next-auth";
|
||||
import * as random_words from "random-words";
|
||||
import { AuditLog, auditLog } from "./audit";
|
||||
import { AliasEntry, AliasRequestEntry, approveAliasEntry, createAliasEntry, createTempAliasRequestEntry, createUserEntry, database, deleteAliasEntry, deleteTempAliasRequestEntry, getAlias, getAllAliases, getTempAliasRequestEntry, getUserAliases, setUserPassword } from "./db";
|
||||
import { aliasesNeedApproval, isAdmin } from "./util";
|
||||
import { TEMP_EMAIL_DOMAIN } from "./constants";
|
||||
|
||||
export async function fetchAllUsers(): Promise<string[]> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
|
@ -28,10 +31,10 @@ export async function changeOwnPassword(newPass: string) {
|
|||
auditLog("changeOwnPassword");
|
||||
}
|
||||
|
||||
export async function fetchOwnAliases() {
|
||||
export async function fetchOwnAliases(tempAliases?: boolean) {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
return await getUserAliases(session.user.email);
|
||||
return await getUserAliases(session.user.email, tempAliases);
|
||||
}
|
||||
|
||||
export async function fetchUserAliases(email: string) {
|
||||
|
@ -50,14 +53,14 @@ export async function fetchAllAliases() {
|
|||
return await getAllAliases();
|
||||
}
|
||||
|
||||
export async function aliasAvailable(email: string) {
|
||||
export async function aliasAvailable(email: string, searchTempRequests: boolean = false) {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user) throw new Error("Unauthenticated");
|
||||
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
db.get('SELECT id FROM aliases WHERE alias = ?', email.toLowerCase(), (err, res) => {
|
||||
db.close();
|
||||
if (!searchTempRequests || err) db.close();
|
||||
if (err) return reject(err);
|
||||
if (res != undefined) return resolve(false);
|
||||
|
||||
|
@ -65,7 +68,17 @@ export async function aliasAvailable(email: string) {
|
|||
authDb.get('SELECT key FROM passwords WHERE key = ?', email.toLowerCase(), (err, res) => {
|
||||
authDb.close();
|
||||
if (err) return reject(err);
|
||||
resolve(res == undefined);
|
||||
|
||||
if (!searchTempRequests) {
|
||||
return resolve(res == undefined);
|
||||
} else {
|
||||
db.get('SELECT key FROM temp_alias_requests WHERE alias = ?', email.toLowerCase(), (err, res) => {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
|
||||
return resolve(res == undefined);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -78,11 +91,13 @@ export async function createAlias(user: string, alias: string): Promise<AliasEnt
|
|||
if (!await aliasAvailable(alias)) throw new Error("Alias unavailable");
|
||||
|
||||
const id = await createAliasEntry(user, alias.toLowerCase(), false);
|
||||
|
||||
const res = {
|
||||
id: id,
|
||||
address: user,
|
||||
alias: alias,
|
||||
pending: false,
|
||||
temporary: false,
|
||||
};
|
||||
|
||||
auditLog('createAlias', res);
|
||||
|
@ -101,13 +116,99 @@ export async function createAliasSelf(alias: string): Promise<AliasEntry> {
|
|||
id: id,
|
||||
address: session.user.email,
|
||||
alias: alias,
|
||||
pending: pending
|
||||
pending: pending,
|
||||
temporary: false,
|
||||
};
|
||||
|
||||
auditLog('requestAlias', res);
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function requestTemporaryAlias(
|
||||
label: string,
|
||||
labelAtEnd: boolean,
|
||||
style: 'words' | 'random',
|
||||
oldToken?: string,
|
||||
): Promise<AliasRequestEntry> {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
|
||||
if (!label.length || label.length > 16) throw new Error("Malformed request");
|
||||
|
||||
let email: string;
|
||||
do {
|
||||
let randomString: string;
|
||||
switch (style) {
|
||||
case 'words':
|
||||
randomString = random_words.generate(2).join('');
|
||||
break;
|
||||
case 'random':
|
||||
randomString = crypto
|
||||
.randomBytes(12)
|
||||
.toString('base64')
|
||||
.replace(/\W/, ''); // Delete special characters
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid style");
|
||||
}
|
||||
email = `${labelAtEnd ? `${randomString}-${label}` : `${label}-${randomString}`}@${TEMP_EMAIL_DOMAIN}`;
|
||||
} while (!await aliasAvailable(email, true));
|
||||
|
||||
const request: AliasRequestEntry = {
|
||||
key: crypto.randomBytes(12).toString('base64'),
|
||||
address: session.user.email,
|
||||
alias: email,
|
||||
expires: Math.floor(Date.now() / 1000) + (60 * 60 * 4), // In 4 hours
|
||||
};
|
||||
|
||||
await createTempAliasRequestEntry(
|
||||
request.key,
|
||||
request.address,
|
||||
request.alias,
|
||||
request.expires,
|
||||
);
|
||||
|
||||
if (oldToken) {
|
||||
await deleteTempAliasRequestEntry(oldToken);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
export async function claimTemporaryAlias(key: string): Promise<AliasEntry> {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
|
||||
const data = await getTempAliasRequestEntry(key);
|
||||
if (!data || data.address != session.user.email) throw new Error("Unknown alias key");
|
||||
|
||||
await deleteTempAliasRequestEntry(key);
|
||||
|
||||
if (data.expires < Math.floor(Date.now() / 1000)) throw new Error("Alias request expired");
|
||||
|
||||
const id = await createAliasEntry(data.address, data.alias, false, true);
|
||||
const alias: AliasEntry = {
|
||||
id: id,
|
||||
address: data.address,
|
||||
alias: data.alias,
|
||||
pending: false,
|
||||
temporary: true,
|
||||
};
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
export async function disposeTempAliasRequest(key: string) {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
|
||||
const data = await getTempAliasRequestEntry(key);
|
||||
if (!data) return;
|
||||
if (data.address != session.user.email) throw new Error("Unauthorized");
|
||||
|
||||
await deleteTempAliasRequestEntry(key);
|
||||
}
|
||||
|
||||
export async function deleteAlias(alias: string) {
|
||||
const session = await getServerSession();
|
||||
if (!session?.user?.email) throw new Error("Unauthenticated");
|
||||
|
@ -161,7 +262,7 @@ export async function fetchAuditLog(page: number): Promise<{ page: number, perPa
|
|||
.split("\n")
|
||||
.reverse();
|
||||
|
||||
if (page > Math.floor(lines.length / itemsPerPage)) {
|
||||
if (page > Math.floor(lines.length / itemsPerPage)) {
|
||||
page = Math.ceil(lines.length / itemsPerPage) - 1;
|
||||
} else if (page < 0) {
|
||||
page = 0;
|
||||
|
|
|
@ -21,7 +21,7 @@ export default function OwnAliasesCard() {
|
|||
const toast = useContext(ToastContext);
|
||||
|
||||
useEffect(() => {
|
||||
fetchOwnAliases().then(setAliases);
|
||||
fetchOwnAliases(false).then(setAliases);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
153
src/lib/components/ui/user/TempAliasesCard.tsx
Normal file
153
src/lib/components/ui/user/TempAliasesCard.tsx
Normal file
|
@ -0,0 +1,153 @@
|
|||
import { disposeTempAliasRequest, fetchOwnAliases, requestTemporaryAlias, claimTemporaryAlias } from "@/lib/actions";
|
||||
import { GRAVATAR_DEFAULT } from "@/lib/constants";
|
||||
import { AliasEntry, AliasRequestEntry } from "@/lib/db";
|
||||
import { sha256sum } from "@/lib/util";
|
||||
import { Avatar, Button, Card, Dialog, Flex, Heading, IconButton, Select, Text, TextField } from "@radix-ui/themes";
|
||||
import { CircleUserIcon, RefreshCcwIcon } from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function TempAliasesCard() {
|
||||
const session = useSession().data;
|
||||
const [aliases, setAliases] = useState<AliasEntry[] | null>(null);
|
||||
const [aliasPreview, setAliasPreview] = useState<AliasRequestEntry | undefined>(undefined);
|
||||
const [aliasLabel, setAliasLabel] = useState("");
|
||||
const [labelAtEnd, setLabelAtEnd] = useState(false);
|
||||
const [aliasStyle, setAliasStyle] = useState<"words" | "random">("words");
|
||||
const [open, setOpen] = useState(false);
|
||||
const [created, setCreated] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchOwnAliases(true).then(setAliases);
|
||||
}, []);
|
||||
|
||||
const refreshAlias = () => {
|
||||
if (aliasPreview?.key) disposeTempAliasRequest(aliasPreview.key); // It's fine if this errors
|
||||
|
||||
if (!aliasLabel) {
|
||||
setAliasPreview(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
requestTemporaryAlias(
|
||||
aliasLabel,
|
||||
labelAtEnd,
|
||||
aliasStyle,
|
||||
aliasPreview?.key,
|
||||
).then(setAliasPreview);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(refreshAlias, [aliasLabel, aliasStyle, labelAtEnd]);
|
||||
|
||||
return (
|
||||
<Card className="h-fit">
|
||||
<Flex direction="row" justify="between" mb="2">
|
||||
<Heading size="3">Temporary aliases</Heading>
|
||||
|
||||
<Dialog.Root open={open} onOpenChange={(open) => {
|
||||
setOpen(open);
|
||||
if (!open) {
|
||||
setAliasLabel("");
|
||||
setLabelAtEnd(false);
|
||||
setAliasStyle("words");
|
||||
setCreated(false);
|
||||
}
|
||||
}}>
|
||||
<Dialog.Trigger>
|
||||
<Button variant="outline" size="1">Generate alias</Button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content>
|
||||
<Dialog.Title>Generate alias</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Temporary aliases can be used to sign up with services without exposing your primary email address.
|
||||
If an alias starts receiving spam or you no longer use the service, you can delete the alias.
|
||||
</Dialog.Description>
|
||||
|
||||
<Flex direction="row" gap="3" mt="4">
|
||||
<Flex direction="column" gap="3" grow="1">
|
||||
<Text ml="1" size="1" color="gray" mb="-1">Alias label</Text>
|
||||
<TextField.Root>
|
||||
<TextField.Slot>
|
||||
<CircleUserIcon size="16" />
|
||||
</TextField.Slot>
|
||||
<TextField.Input
|
||||
placeholder="Alias label"
|
||||
value={aliasLabel}
|
||||
onChange={(e) => setAliasLabel(e.currentTarget.value.substring(0, 16))}
|
||||
/>
|
||||
</TextField.Root>
|
||||
</Flex>
|
||||
|
||||
<Flex direction="column" gap="3">
|
||||
<Text ml="1" size="1" color="gray" mb="-1">Alias style</Text>
|
||||
<Select.Root value={aliasStyle} onValueChange={(value) => setAliasStyle(value as any)}>
|
||||
<Select.Trigger />
|
||||
<Select.Content>
|
||||
<Select.Group>
|
||||
<Select.Label>Alias style</Select.Label>
|
||||
<Select.Item value="words">Words</Select.Item>
|
||||
<Select.Item value="random">Random</Select.Item>
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Flex>
|
||||
|
||||
<Flex direction="column" gap="3">
|
||||
<Text ml="1" size="1" color="gray" mb="-1">Label position</Text>
|
||||
<Select.Root value={labelAtEnd ? "after" : "before"} onValueChange={(value) => setLabelAtEnd(value == "after")}>
|
||||
<Select.Trigger />
|
||||
<Select.Content>
|
||||
<Select.Group>
|
||||
<Select.Label>Alias style</Select.Label>
|
||||
<Select.Item value="before">Label first</Select.Item>
|
||||
<Select.Item value="after">Label at end</Select.Item>
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Card mt="4">
|
||||
<Flex direction="row" justify="between" align="center">
|
||||
<Flex direction="row" align="center" gap="3">
|
||||
<Avatar
|
||||
size="3"
|
||||
src={`https://gravatar.com/avatar/${sha256sum(aliasPreview?.alias || "")}?d=${GRAVATAR_DEFAULT}`}
|
||||
fallback={"@"}
|
||||
/>
|
||||
<Flex direction="column" gap="0">
|
||||
<Text size="3" weight="medium">Generated alias</Text>
|
||||
<Text size="2" weight="light">{aliasPreview?.alias || "Enter a label first"}</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<IconButton onClick={() => refreshAlias()} disabled={!aliasLabel} variant="surface" size="2">
|
||||
<RefreshCcwIcon size="16" />
|
||||
</IconButton>
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
<Flex gap="3" mt="4" justify="end">
|
||||
<Dialog.Close>
|
||||
<Button variant="outline">Close</Button>
|
||||
</Dialog.Close>
|
||||
<Button
|
||||
disabled={!aliasPreview}
|
||||
variant="soft"
|
||||
onClick={async () => {
|
||||
try {
|
||||
//const alias = await claimTemporaryAlias(aliasPreview!.key);
|
||||
} catch(e) {
|
||||
setOpen(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Flex>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
</Flex>
|
||||
<Text weight="light" size="2">Freely generate and dispose of randomized aliases.</Text>
|
||||
</Card>
|
||||
);
|
||||
}
|
|
@ -8,4 +8,5 @@ export const SMTP_SECURITY = "SSL/TLS";
|
|||
export const IMAP_SECURITY = "SSL/TLS";
|
||||
export const WEBMAIL_URL = "https://webmail.amogus.cloud";
|
||||
export const ALIAS_DOMAINS = ["amogus.cloud", "lea.pet", "futacockinside.me"];
|
||||
export const GRAVATAR_DEFAULT = "retro";
|
||||
export const GRAVATAR_DEFAULT = "retro";
|
||||
export const TEMP_EMAIL_DOMAIN = "t.amogus.cloud";
|
|
@ -2,6 +2,9 @@ import sqlite from "sqlite3";
|
|||
import bcrypt from "bcryptjs";
|
||||
import { PHASE_PRODUCTION_BUILD } from "next/dist/shared/lib/constants";
|
||||
|
||||
export type AliasEntry = { id: number, address: string, alias: string, pending: boolean, temporary: boolean };
|
||||
export type AliasRequestEntry = { key: string, address: string, alias: string, expires: number };
|
||||
|
||||
export const database = (type: 'credentials' | 'aliases') => {
|
||||
if (process.env.NEXT_PHASE != PHASE_PRODUCTION_BUILD) {
|
||||
for (const v of ["CREDENTIALS_DB_PATH", "ALIASES_DB_PATH"]) {
|
||||
|
@ -75,7 +78,6 @@ export function setUserPassword(email: string, newPass: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export type AliasEntry = { id: number, address: string, alias: string, pending: boolean };
|
||||
export function getAllAliases() {
|
||||
return new Promise<AliasEntry[]>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
@ -86,22 +88,31 @@ export function getAllAliases() {
|
|||
resolve(res.map((data) => ({
|
||||
...data,
|
||||
pending: !!data.pending,
|
||||
temporary: !!data.temporary,
|
||||
})));
|
||||
});
|
||||
});
|
||||
}
|
||||
export function getUserAliases(email: string) {
|
||||
|
||||
export function getUserAliases(email: string, tempAliases?: boolean) {
|
||||
return new Promise<AliasEntry[]>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
||||
db.all("SELECT id, address, alias, pending FROM aliases WHERE address = ?", email, (err, res: any[]) => {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve(res.map((data) => ({
|
||||
...data,
|
||||
pending: !!data.pending,
|
||||
})));
|
||||
});
|
||||
db.all(
|
||||
"SELECT id, address, alias, pending FROM aliases WHERE address = ?1 " + (typeof tempAliases != 'undefined' ? "AND temporary = ?2" : ""),
|
||||
{
|
||||
1: email,
|
||||
2: tempAliases ? 1 : 0,
|
||||
},
|
||||
(err, res: any[]) => {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve(res.map((data) => ({
|
||||
...data,
|
||||
pending: !!data.pending,
|
||||
temporary: !!data.temporary,
|
||||
})));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -116,23 +127,25 @@ export function getAlias(alias: string) {
|
|||
resolve({
|
||||
...res,
|
||||
pending: !!res.pending,
|
||||
temporary: !!res.temporary,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function createAliasEntry(user: string, alias: string, pending: boolean) {
|
||||
export function createAliasEntry(user: string, alias: string, pending: boolean, temporary: boolean = false) {
|
||||
return new Promise<number>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
||||
db.run(
|
||||
"INSERT INTO aliases (address, alias, pending) VALUES (?1, ?2, ?3)",
|
||||
"INSERT INTO aliases (address, alias, pending, temporary) VALUES (?1, ?2, ?3, ?4)",
|
||||
{
|
||||
1: user,
|
||||
2: alias,
|
||||
3: pending ? 1 : 0,
|
||||
4: temporary ? 1 : 0,
|
||||
},
|
||||
function(err: any) {
|
||||
function (err: any) {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve(this.lastID);
|
||||
|
@ -140,6 +153,56 @@ export function createAliasEntry(user: string, alias: string, pending: boolean)
|
|||
});
|
||||
}
|
||||
|
||||
export function createTempAliasRequestEntry(key: string, account: string, alias: string, expires: number) {
|
||||
return new Promise<number>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
||||
db.run(
|
||||
"INSERT INTO temp_alias_requests (key, address, alias, expires) VALUES (?1, ?2, ?3, ?4)",
|
||||
{
|
||||
1: key,
|
||||
2: account,
|
||||
3: alias,
|
||||
4: expires,
|
||||
},
|
||||
function (err: any) {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve(this.lastID);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getTempAliasRequestEntry(key: string) {
|
||||
return new Promise<AliasRequestEntry | undefined>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
||||
db.get(
|
||||
"SELECT key, address, alias, expires FROM temp_alias_requests WHERE key = ?",
|
||||
key,
|
||||
function (err, res: any) {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteTempAliasRequestEntry(key: string) {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
||||
db.run(
|
||||
"DELETE FROM temp_alias_requests WHERE key = ?",
|
||||
key,
|
||||
function (err: any) {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function approveAliasEntry(alias: string) {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
const db = database('aliases');
|
||||
|
@ -147,7 +210,7 @@ export function approveAliasEntry(alias: string) {
|
|||
db.run(
|
||||
"UPDATE aliases SET pending = 0 WHERE alias = ?",
|
||||
alias,
|
||||
function(err: any) {
|
||||
function (err: any) {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
|
@ -162,7 +225,7 @@ export function deleteAliasEntry(alias: string) {
|
|||
db.run(
|
||||
"DELETE FROM aliases WHERE alias = ?",
|
||||
alias,
|
||||
function(err: any) {
|
||||
function (err: any) {
|
||||
db.close();
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
|
|
Loading…
Reference in a new issue