-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.js
148 lines (129 loc) · 4.83 KB
/
client.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// ==UserScript==
// @name Cloudflare Email Free
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Make possible to use cloudflare workers to send emails from gmail interface, adds a button to the gmail compose interface
// @author Fptbb/HasteD
// @match *mail.google.com/*
// @icon https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico
// @grant GM_xmlhttpRequest
// ==/UserScript==
const Api = 'Api Defined in Cloudflare Workers'
const Authorization = 'Random Strong Authorization Key'
function GM_fetch(url, opt) {
function blobTo(to, blob) {
if (to == "arrayBuffer" && blob.arrayBuffer) return blob.arrayBuffer()
return new Promise((resolve, reject) => {
var fileReader = new FileReader()
fileReader.onload = function (event) { if (to == "base64") resolve(event.target.result); else resolve(event.target.result) }
if (to == "arrayBuffer") fileReader.readAsArrayBuffer(blob)
else if (to == "base64") fileReader.readAsDataURL(blob) // "data:*/*;base64,......"
else if (to == "text") fileReader.readAsText(blob, "utf-8")
else reject("unknown to")
})
}
return new Promise((resolve, reject) => {
// https://www.tampermonkey.net/documentation.php?ext=dhdg#GM_xmlhttpRequest
opt = opt || {}
opt.url = url
opt.data = opt.body
opt.responseType = "blob"
opt.onload = (resp) => {
var blob = resp.response
resp.blob = () => Promise.resolve(blob)
resp.arrayBuffer = () => blobTo("arrayBuffer", blob)
resp.text = () => blobTo("text", blob)
resp.json = async () => JSON.parse(await blobTo("text", blob))
resolve(resp)
}
opt.ontimeout = () => reject("fetch timeout")
opt.onerror = (err) => reject(err)
opt.onabort = () => reject("fetch abort")
GM_xmlhttpRequest(opt)
})
}
const hookButton = (button) => {
if (button.getAttribute('__hooked__')) return
button.setAttribute('__hooked__', true)
const form =
button.parentElement?.parentElement?.parentElement?.querySelector('form')
if (!form) return alert('No form found')
const newNode = button.cloneNode(true)
newNode.setAttribute('selector', 'Webhook')
newNode.setAttribute('id', '')
newNode.style = 'user-select: none; cursor: pointer;'
newNode.addEventListener('mouseover', () => {
newNode.style.backgroundColor = '#f0f0f0'
})
newNode.addEventListener('mouseout', () => {
newNode.style.backgroundColor = '#ffffff'
})
newNode.addEventListener('click', () => {
const subjectBox = form.querySelector('input[name="subjectbox"]')
const textArea = form.parentElement?.querySelector('div[role="textbox"]')
const emailList = [
...new Set(
[...form.querySelectorAll('input[value]')].map((e) => {
console.log(e)
if (e.getAttribute('name') === 'to' || e.getAttribute('name') === 'cc' || e.getAttribute('name') === 'bcc') {
if (/(.*) \<([\w\.]+@[\w-]+\.+[\w-]{2,4})\>/g.test(e.getAttribute('value'))) {
let regex = /(.*) \<([\w\.]+@[\w-]+\.+[\w-]{2,4})\>/g.exec(e.getAttribute('value'))
return {
email: regex[2],
type: e.getAttribute('name'),
name: regex[1]
}
} else {
return {
email: e.getAttribute('value'),
type: 'normal'
}
}
}
})
),
]
if (
!subjectBox ||
subjectBox.value === '' ||
emailList.length <= 0 ||
!textArea ||
textArea.innerHTML === ''
) return alert('Invalid form')
const deleteList = form.parentElement
?.querySelector('[command="Files"]')
?.closest('tr').lastElementChild
const deleteButton =
deleteList &&
[...deleteList.querySelectorAll('[tabindex="1"][role="button"]')].pop()
if (!deleteButton) return alert('No delete button found')
var data = JSON.stringify({
email: emailList.filter((el => el != undefined),
subject: subjectBox.value,
})
GM_fetch(Api, {
method: 'POST',
body: textArea.innerHTML,
headers: {
'Content-Type': 'text/html;charset=UTF-8',
'data': data,
'Authorization': Authorization,
}
}).then(resp => resp.text()).then(resp => {
deleteButton.click()
alert('Email sent!')
}).catch((e) => {
console.log(e)
alert(`Failed to send email: ${e.message}`)
})
})
newNode.querySelector('img').parentElement.innerHTML = 'Webhook Send'
button.parentElement.appendChild(newNode)
}
new MutationObserver((mutations) => {
mutations.forEach(({ target }) => {
const tweet = target.closest('[selector="scheduledSend"]')
tweet && hookButton(tweet)
})
}).observe(document.body, { childList: true, subtree: true })
document.querySelectorAll('[selector="scheduledSend"]').forEach(hookButton)