mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-06 20:32:55 +08:00
feat: add custom address (#13)
* feat: add custom address * feat: update readme
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
- [x] 使用 Cloudflare Workers 部署后端
|
||||
- [x] email 转发使用 Cloudflare Email Routing
|
||||
- [x] 使用 password 重新登录之前的邮箱
|
||||
- [x] 获取自定义名字的邮箱
|
||||
- [ ] 免费版附件过大会造成 Exceeded CPU Limit 错误
|
||||
|
||||
---
|
||||
|
||||
@@ -13,6 +13,7 @@ This is a temporary email service that uses Cloudflare Workers to create a tempo
|
||||
- [x] Deploy the backend with Cloudflare Workers
|
||||
- [x] Email forwarding using Cloudflare Email Routing
|
||||
- [x] Use password to login to the previous mailbox again.
|
||||
- [x] Get Custom Name Email
|
||||
- [ ] Exceeded CPU Limit error caused by the free version of the attachment
|
||||
|
||||

|
||||
|
||||
2
frontend/.gitignore
vendored
2
frontend/.gitignore
vendored
@@ -27,4 +27,4 @@ coverage
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env.local
|
||||
.env.*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import { NMessageProvider, NGrid, NBackTop, NLayoutHeader, NInput } from 'naive-ui'
|
||||
import { NGi, NSpace, NButton, NConfigProvider, NSelect, NModal } from 'naive-ui'
|
||||
import { darkTheme, NSwitch, NGlobalStyle } from 'naive-ui'
|
||||
import { darkTheme, NSwitch, NGlobalStyle, NPopconfirm } from 'naive-ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
|
||||
@@ -17,6 +17,10 @@ const login = () => {
|
||||
jwt.value = password.value;
|
||||
location.reload()
|
||||
}
|
||||
const logout = () => {
|
||||
jwt.value = '';
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -41,7 +45,17 @@ const login = () => {
|
||||
Light
|
||||
</template>
|
||||
</n-switch>
|
||||
<n-button tertiary @click="showLogin = true" round type="primary">
|
||||
<n-popconfirm v-if="jwt" @positive-click="logout">
|
||||
<template #trigger>
|
||||
<n-button tertiary round type="primary">
|
||||
Logout
|
||||
</n-button>
|
||||
</template>
|
||||
<template #default>
|
||||
<span>Are you sure to logout?</span>
|
||||
</template>
|
||||
</n-popconfirm>
|
||||
<n-button v-else tertiary @click="showLogin = true" round type="primary">
|
||||
Login
|
||||
</n-button>
|
||||
<n-button tag="a" target="_blank" tertiary type="primary" round
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { NSpace, NAlert, NSwitch, NCard } from 'naive-ui'
|
||||
import { NSpin, NButton, NLayout, NPopconfirm, NModal } from 'naive-ui'
|
||||
import { NSpace, NAlert, NSwitch, NCard, NInput, NInputGroupLabel } from 'naive-ui'
|
||||
import { NSpin, NButton, NLayout, NInputGroup, NModal } from 'naive-ui'
|
||||
import { NList, NListItem, NThing, NTag, NNumberAnimation } from 'naive-ui'
|
||||
import { watch, onMounted, ref } from "vue";
|
||||
import { useStorage } from '@vueuse/core'
|
||||
@@ -18,6 +18,12 @@ const data = ref([])
|
||||
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
||||
const timer = ref(null)
|
||||
const showPassword = ref(false)
|
||||
const showNewEmail = ref(false)
|
||||
const emailName = ref("")
|
||||
const openSettings = ref({
|
||||
prefix: 'test',
|
||||
domain: 'test.com'
|
||||
})
|
||||
|
||||
const setupAutoRefresh = async (autoRefresh) => {
|
||||
if (autoRefresh) {
|
||||
@@ -74,7 +80,11 @@ const copy = async () => {
|
||||
const newEmail = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await fetch(`${API_BASE}/api/new_address`, {
|
||||
let url = `${API_BASE}/api/new_address`;
|
||||
if (emailName.value) {
|
||||
url = `${url}?name=${emailName.value}`;
|
||||
}
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
@@ -82,24 +92,38 @@ const newEmail = async () => {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
message.error(
|
||||
`${response.status} ${await response.text()}` || "error",
|
||||
);
|
||||
throw new Error(`${response.status} ${await response.text()}` || "error");
|
||||
}
|
||||
let res = await response.json();
|
||||
jwt.value = res["jwt"];
|
||||
await refresh();
|
||||
showNewEmail.value = false;
|
||||
showPassword.value = true;
|
||||
} catch (error) {
|
||||
jwt.value = "";
|
||||
message.error(error.message || "error");
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
await refresh();
|
||||
showPassword.value = true;
|
||||
};
|
||||
|
||||
const getOpenSettings = async (jwt) => {
|
||||
const response = await fetch(`${API_BASE}/open_api/settings`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
message.error(`${response.status} ${await response.text()}` || "error");
|
||||
console.error(response);
|
||||
return;
|
||||
}
|
||||
let res = await response.json();
|
||||
openSettings.value = res;
|
||||
}
|
||||
|
||||
const getSettings = async (jwt) => {
|
||||
if (typeof jwt != 'string' || jwt.trim() === '' || jwt === 'undefined') {
|
||||
return;
|
||||
@@ -126,6 +150,7 @@ const getSettings = async (jwt) => {
|
||||
watch(jwt, async (jwt, old) => getSettings(jwt))
|
||||
|
||||
onMounted(async () => {
|
||||
getOpenSettings()
|
||||
getSettings(jwt.value)
|
||||
await refresh();
|
||||
const token = import.meta.env.VITE_CF_WEB_ANALY_TOKEN;
|
||||
@@ -156,17 +181,12 @@ onMounted(async () => {
|
||||
Please click <b>Get New Email</b> button to get a new email address
|
||||
</span>
|
||||
</n-alert>
|
||||
<n-button class="center" @click="showPassword = true" tertiary round type="primary">
|
||||
<n-button v-if="address" class="center" @click="showPassword = true" tertiary round type="primary">
|
||||
Show Password
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="newEmail" :show-icon="false">
|
||||
<template #trigger>
|
||||
<n-button class="center" tertiary round type="primary">
|
||||
Get New Email
|
||||
</n-button>
|
||||
</template>
|
||||
Get New Email?
|
||||
</n-popconfirm>
|
||||
<n-button v-else class="center" @click="showNewEmail = true" tertiary round type="primary">
|
||||
Get New Email
|
||||
</n-button>
|
||||
<n-switch v-model:value="autoRefresh">
|
||||
<template #checked>
|
||||
Auto Refresh
|
||||
@@ -195,6 +215,32 @@ onMounted(async () => {
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-layout>
|
||||
<n-modal v-model:show="showNewEmail" preset="dialog" title="Dialog">
|
||||
<template #header>
|
||||
<div>Get New Email</div>
|
||||
</template>
|
||||
<span>
|
||||
<p>Please input the email you want to use.</p>
|
||||
<p>Levaing it blank will generate a random email address.</p>
|
||||
</span>
|
||||
<n-input-group>
|
||||
<n-input-group-label v-if="openSettings.prefix">
|
||||
{{ openSettings.prefix }}
|
||||
</n-input-group-label>
|
||||
<n-input v-model:value="emailName" />
|
||||
<n-input-group-label>
|
||||
@{{ openSettings.domain }}
|
||||
</n-input-group-label>
|
||||
</n-input-group>
|
||||
<template #action>
|
||||
<n-button @click="showNewEmail = false">
|
||||
Cancel
|
||||
</n-button>
|
||||
<n-button @click="newEmail" type="primary">
|
||||
OK
|
||||
</n-button>
|
||||
</template>
|
||||
</n-modal>
|
||||
<n-modal v-model:show="showPassword" preset="dialog" title="Dialog">
|
||||
<template #header>
|
||||
<div>Password</div>
|
||||
|
||||
@@ -18,14 +18,31 @@ api.get('/api/settings', async (c) => {
|
||||
return c.json(c.get("jwtPayload"));
|
||||
})
|
||||
|
||||
api.get('/open_api/settings', async (c) => {
|
||||
return c.json({
|
||||
"prefix": c.env.PREFIX,
|
||||
"domain": c.env.DOMAIN,
|
||||
});
|
||||
})
|
||||
|
||||
api.get('/api/new_address', async (c) => {
|
||||
// insert new address
|
||||
const name = Math.random().toString(36).substring(2, 15)
|
||||
const { success } = await c.env.DB.prepare(
|
||||
`INSERT INTO address (name) VALUES (?)`
|
||||
).bind(name).run();
|
||||
if (!success) {
|
||||
return c.json({ "error": "Failed to create address" }, 500)
|
||||
let { name } = await c.req.query();
|
||||
if (!name) {
|
||||
name = Math.random().toString(36).substring(2, 15)
|
||||
}
|
||||
try {
|
||||
const { success } = await c.env.DB.prepare(
|
||||
`INSERT INTO address (name) VALUES (?)`
|
||||
).bind(name).run();
|
||||
if (!success) {
|
||||
return c.text("Failed to create address", 500)
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.message && e.message.includes("UNIQUE")) {
|
||||
return c.text("Please retry a new address", 400)
|
||||
}
|
||||
return c.text("Failed to create address", 500)
|
||||
}
|
||||
// create jwt
|
||||
const jwt = await Jwt.sign({
|
||||
|
||||
Reference in New Issue
Block a user