tempmail_sdk 1.3.4 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/tempmail_sdk/channels.rb +29 -7
- data/lib/tempmail_sdk/channels_data.rb +29 -7
- data/lib/tempmail_sdk/providers/clawdemail.rb +122 -0
- data/lib/tempmail_sdk/providers/crazymailing.rb +114 -0
- data/lib/tempmail_sdk/providers/firetempmail.rb +86 -0
- data/lib/tempmail_sdk/providers/flybymail.rb +93 -0
- data/lib/tempmail_sdk/providers/generator_email.rb +146 -0
- data/lib/tempmail_sdk/providers/huskmail.rb +132 -0
- data/lib/tempmail_sdk/providers/internxt.rb +176 -0
- data/lib/tempmail_sdk/providers/linshi_xyz.rb +79 -0
- data/lib/tempmail_sdk/providers/mailmomy.rb +1 -1
- data/lib/tempmail_sdk/providers/mailticking.rb +139 -0
- data/lib/tempmail_sdk/providers/mtempmail.rb +140 -0
- data/lib/tempmail_sdk/providers/nowtempmail.rb +112 -0
- data/lib/tempmail_sdk/providers/noxen_de5_net.rb +392 -0
- data/lib/tempmail_sdk/providers/nukemail.rb +188 -0
- data/lib/tempmail_sdk/providers/nullmail.rb +95 -0
- data/lib/tempmail_sdk/providers/shadowmail.rb +174 -0
- data/lib/tempmail_sdk/providers/shitpost_email.rb +85 -0
- data/lib/tempmail_sdk/providers/smails.rb +128 -0
- data/lib/tempmail_sdk/providers/temp_mail_gg.rb +362 -0
- data/lib/tempmail_sdk/providers/tempmail100.rb +148 -0
- data/lib/tempmail_sdk/providers/tempmail_ee.rb +373 -0
- data/lib/tempmail_sdk/providers/tempmailportal.rb +131 -0
- data/lib/tempmail_sdk/providers/tempmails_io.rb +89 -0
- data/lib/tempmail_sdk/providers/tempmailto.rb +312 -0
- data/lib/tempmail_sdk/providers/temporarymail_com.rb +184 -0
- data/lib/tempmail_sdk/providers/tenmin_app.rb +100 -0
- data/lib/tempmail_sdk/providers/thirty_min_email.rb +90 -0
- data/lib/tempmail_sdk/providers/tmpkit.rb +129 -0
- data/lib/tempmail_sdk/providers/zerodrop.rb +90 -0
- data/lib/tempmail_sdk/registry.rb +129 -29
- data/lib/tempmail_sdk/types.rb +13 -0
- data/lib/tempmail_sdk/version.rb +1 -1
- data/lib/tempmail_sdk.rb +1 -1
- metadata +31 -7
- data/lib/tempmail_sdk/providers/gonebox_email.rb +0 -89
- data/lib/tempmail_sdk/providers/mohmal.rb +0 -208
- data/lib/tempmail_sdk/providers/temp_mail_now.rb +0 -103
- data/lib/tempmail_sdk/providers/webmailtemp.rb +0 -108
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module TempmailSdk
|
|
4
|
-
module Providers
|
|
5
|
-
# gonebox.email 渠道实现
|
|
6
|
-
# 一次性临时邮箱服务,无需认证
|
|
7
|
-
module GoneboxEmail
|
|
8
|
-
CHANNEL = "gonebox-email"
|
|
9
|
-
BASE_URL = "https://api.gonebox.email/api/v1"
|
|
10
|
-
HEADERS = {
|
|
11
|
-
"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
|
|
12
|
-
"(KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
|
13
|
-
"Accept" => "application/json",
|
|
14
|
-
"Content-Type" => "application/json"
|
|
15
|
-
}.freeze
|
|
16
|
-
|
|
17
|
-
module_function
|
|
18
|
-
|
|
19
|
-
# @return [EmailInfo]
|
|
20
|
-
def generate_email
|
|
21
|
-
resp = Http.post(
|
|
22
|
-
"#{BASE_URL}/inboxes",
|
|
23
|
-
headers: HEADERS,
|
|
24
|
-
json: { "domain" => "gonebox.email" },
|
|
25
|
-
timeout: 15
|
|
26
|
-
)
|
|
27
|
-
resp.raise_for_status
|
|
28
|
-
body = resp.json
|
|
29
|
-
raise "gonebox-email: create failed" unless body.is_a?(Hash) && body["success"]
|
|
30
|
-
|
|
31
|
-
data = body["data"]
|
|
32
|
-
raise "gonebox-email: invalid data" unless data.is_a?(Hash)
|
|
33
|
-
|
|
34
|
-
address = data["address"].to_s
|
|
35
|
-
raise "gonebox-email: missing address" if address.empty?
|
|
36
|
-
|
|
37
|
-
# expiresAt 为秒级时间戳,转为毫秒
|
|
38
|
-
expires_at = nil
|
|
39
|
-
raw_expires = data["expiresAt"]
|
|
40
|
-
if raw_expires
|
|
41
|
-
begin
|
|
42
|
-
expires_at = raw_expires.to_i * 1000
|
|
43
|
-
rescue StandardError
|
|
44
|
-
# 忽略
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
EmailInfo.new(channel: CHANNEL, email: address, token: "", expires_at: expires_at)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @param token [String]
|
|
52
|
-
# @param email [String]
|
|
53
|
-
# @return [Array<Email>]
|
|
54
|
-
def get_emails(token, email)
|
|
55
|
-
address = email.to_s.strip
|
|
56
|
-
raise "gonebox-email: missing email" if address.empty?
|
|
57
|
-
|
|
58
|
-
headers = HEADERS.reject { |k, _| k == "Content-Type" }
|
|
59
|
-
resp = Http.get("#{BASE_URL}/inboxes/#{address}/messages", headers: headers, timeout: 15)
|
|
60
|
-
return [] if resp.status_code == 404
|
|
61
|
-
|
|
62
|
-
resp.raise_for_status
|
|
63
|
-
body = resp.json
|
|
64
|
-
return [] unless body.is_a?(Hash) && body["success"]
|
|
65
|
-
|
|
66
|
-
data = body["data"]
|
|
67
|
-
return [] unless data.is_a?(Hash)
|
|
68
|
-
|
|
69
|
-
messages = data["messages"]
|
|
70
|
-
return [] unless messages.is_a?(Array) && !messages.empty?
|
|
71
|
-
|
|
72
|
-
messages.select { |m| m.is_a?(Hash) }.map do |msg|
|
|
73
|
-
raw = {
|
|
74
|
-
"id" => msg["id"].to_s,
|
|
75
|
-
"from" => (msg["from"] || msg["sender"]).to_s,
|
|
76
|
-
"to" => address,
|
|
77
|
-
"subject" => msg["subject"].to_s,
|
|
78
|
-
"text" => (msg["text"] || msg["body_plain"]).to_s,
|
|
79
|
-
"html" => (msg["html"] || msg["body_html"]).to_s,
|
|
80
|
-
"date" => (msg["date"] || msg["received_at"]).to_s,
|
|
81
|
-
"is_read" => false,
|
|
82
|
-
"attachments" => []
|
|
83
|
-
}
|
|
84
|
-
Normalize.normalize_email(raw, address)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "cgi"
|
|
4
|
-
|
|
5
|
-
module TempmailSdk
|
|
6
|
-
module Providers
|
|
7
|
-
# mohmal.com 渠道实现(HTML 页面解析,session cookie)
|
|
8
|
-
#
|
|
9
|
-
# 流程:GET /en/create/random 创建邮箱(跟随重定向到 /en/inbox),从 data-email 属性提取邮箱地址
|
|
10
|
-
# GET /en/inbox 解析邮件链接列表
|
|
11
|
-
# GET /en/message/{id}/html 获取邮件详情
|
|
12
|
-
# token 存储 connect.sid cookie 字符串
|
|
13
|
-
# 注意:正文提取使用栈式深度匹配,避免非贪婪正则截断嵌套 div
|
|
14
|
-
module Mohmal
|
|
15
|
-
CHANNEL = "mohmal"
|
|
16
|
-
BASE_URL = "https://www.mohmal.com"
|
|
17
|
-
|
|
18
|
-
DATA_EMAIL_RE = /data-email=["']([^"']+)["']/im
|
|
19
|
-
MSG_HREF_RE = /href=["'](\/en\/message\/([^"']+))["']/i
|
|
20
|
-
DETAIL_FROM_RE = /<span[^>]+class=["'][^"']*from[^"']*["'][^>]*>([\s\S]*?)<\/span>/im
|
|
21
|
-
DETAIL_SUBJECT_RE = /<span[^>]+class=["'][^"']*subject[^"']*["'][^>]*>([\s\S]*?)<\/span>/im
|
|
22
|
-
DETAIL_DATE_RE = /<span[^>]+class=["'][^"']*date[^"']*["'][^>]*>([\s\S]*?)<\/span>/im
|
|
23
|
-
TAG_RE = /<[^>]+>/
|
|
24
|
-
BODY_OPEN_RE = /<div\s+class=["'][^"']*(?:mail-body|message-body|message_body)[^"']*["']\s*>/im
|
|
25
|
-
|
|
26
|
-
BROWSER_HEADERS = {
|
|
27
|
-
"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
|
|
28
|
-
"(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0",
|
|
29
|
-
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif," \
|
|
30
|
-
"image/webp,image/apng,*/*;q=0.8",
|
|
31
|
-
"Accept-Language" => "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
|
|
32
|
-
"Cache-Control" => "no-cache",
|
|
33
|
-
"DNT" => "1",
|
|
34
|
-
"Pragma" => "no-cache",
|
|
35
|
-
"Upgrade-Insecure-Requests" => "1"
|
|
36
|
-
}.freeze
|
|
37
|
-
|
|
38
|
-
module_function
|
|
39
|
-
|
|
40
|
-
# 从 HTML 中提取 data-email 属性值
|
|
41
|
-
# @param html [String]
|
|
42
|
-
# @return [String]
|
|
43
|
-
def extract_email(html)
|
|
44
|
-
m = html.match(DATA_EMAIL_RE)
|
|
45
|
-
m ? CGI.unescapeHTML(m[1].strip) : ""
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# 合并 Cookie 头与响应 Set-Cookie
|
|
49
|
-
# @param existing [String]
|
|
50
|
-
# @param set_cookie_lines [Array<String>]
|
|
51
|
-
# @return [String]
|
|
52
|
-
def merge_cookies(existing, set_cookie_lines)
|
|
53
|
-
map = {}
|
|
54
|
-
existing.to_s.split(";").each do |part|
|
|
55
|
-
part = part.strip
|
|
56
|
-
next unless part.include?("=")
|
|
57
|
-
|
|
58
|
-
k, v = part.split("=", 2)
|
|
59
|
-
map[k.strip] = v.to_s.strip unless k.strip.empty?
|
|
60
|
-
end
|
|
61
|
-
set_cookie_lines.each do |line|
|
|
62
|
-
pair = line.split(";", 2).first.to_s.strip
|
|
63
|
-
next unless pair.include?("=")
|
|
64
|
-
|
|
65
|
-
k, v = pair.split("=", 2)
|
|
66
|
-
map[k.strip] = v.to_s.strip unless k.strip.empty?
|
|
67
|
-
end
|
|
68
|
-
map.map { |k, v| "#{k}=#{v}" }.join("; ")
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# 去除 HTML 标签并修剪空白
|
|
72
|
-
# @param s [String]
|
|
73
|
-
# @return [String]
|
|
74
|
-
def strip_tags(s)
|
|
75
|
-
s.gsub(TAG_RE, " ").strip
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# 使用栈式深度匹配提取指定 class 的 div 完整内部 HTML
|
|
79
|
-
# 避免非贪婪正则在嵌套 div 时截断正文
|
|
80
|
-
# @param page [String]
|
|
81
|
-
# @return [String]
|
|
82
|
-
def extract_body_html(page)
|
|
83
|
-
m = page.match(BODY_OPEN_RE)
|
|
84
|
-
return "" unless m
|
|
85
|
-
|
|
86
|
-
start = m.end(0)
|
|
87
|
-
pos = start
|
|
88
|
-
depth = 1
|
|
89
|
-
while pos < page.length && depth > 0
|
|
90
|
-
next_open = page.index("<div", pos)
|
|
91
|
-
next_close = page.index("</div>", pos)
|
|
92
|
-
break unless next_close
|
|
93
|
-
|
|
94
|
-
if next_open && next_open < next_close
|
|
95
|
-
depth += 1
|
|
96
|
-
pos = next_open + 4
|
|
97
|
-
else
|
|
98
|
-
depth -= 1
|
|
99
|
-
return page[start...next_close].strip if depth.zero?
|
|
100
|
-
|
|
101
|
-
pos = next_close + 6
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
""
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# 创建 mohmal.com 临时邮箱
|
|
108
|
-
# @return [EmailInfo]
|
|
109
|
-
def generate_email
|
|
110
|
-
r1 = Http.get(
|
|
111
|
-
BASE_URL + "/en/create/random",
|
|
112
|
-
headers: BROWSER_HEADERS.merge("Referer" => BASE_URL + "/en"),
|
|
113
|
-
timeout: 15
|
|
114
|
-
)
|
|
115
|
-
r1.raise_for_status
|
|
116
|
-
cookie_hdr = merge_cookies("", r1.set_cookies)
|
|
117
|
-
email = extract_email(r1.body)
|
|
118
|
-
|
|
119
|
-
if email.empty?
|
|
120
|
-
r2 = Http.get(
|
|
121
|
-
BASE_URL + "/en/inbox",
|
|
122
|
-
headers: BROWSER_HEADERS.merge("Referer" => BASE_URL + "/en", "Cookie" => cookie_hdr),
|
|
123
|
-
timeout: 15
|
|
124
|
-
)
|
|
125
|
-
r2.raise_for_status
|
|
126
|
-
cookie_hdr = merge_cookies(cookie_hdr, r2.set_cookies)
|
|
127
|
-
email = extract_email(r2.body)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
raise "mohmal: 未能从页面中提取邮箱地址" if email.empty?
|
|
131
|
-
|
|
132
|
-
EmailInfo.new(channel: CHANNEL, email: email, token: cookie_hdr)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# 获取 mohmal.com 邮件列表
|
|
136
|
-
# @param email [String]
|
|
137
|
-
# @param token [String] connect.sid cookie 字符串
|
|
138
|
-
# @return [Array<Email>]
|
|
139
|
-
def get_emails(email, token)
|
|
140
|
-
raise "mohmal: session cookie 为空" if token.to_s.strip.empty?
|
|
141
|
-
|
|
142
|
-
r = Http.get(
|
|
143
|
-
BASE_URL + "/en/inbox",
|
|
144
|
-
headers: BROWSER_HEADERS.merge(
|
|
145
|
-
"Referer" => BASE_URL + "/en",
|
|
146
|
-
"Cookie" => token
|
|
147
|
-
),
|
|
148
|
-
timeout: 15
|
|
149
|
-
)
|
|
150
|
-
r.raise_for_status
|
|
151
|
-
|
|
152
|
-
seen = {}
|
|
153
|
-
msgs = []
|
|
154
|
-
r.body.scan(MSG_HREF_RE) do |path, id|
|
|
155
|
-
next if path.include?("/delete")
|
|
156
|
-
next if seen[id]
|
|
157
|
-
|
|
158
|
-
seen[id] = true
|
|
159
|
-
msgs << { path: path, id: id }
|
|
160
|
-
end
|
|
161
|
-
return [] if msgs.empty?
|
|
162
|
-
|
|
163
|
-
msgs.filter_map do |msg|
|
|
164
|
-
raw = fetch_detail(token, msg[:id], email)
|
|
165
|
-
Normalize.normalize_email(raw, email)
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# 获取单封邮件详情页
|
|
170
|
-
# @param cookie [String]
|
|
171
|
-
# @param id [String]
|
|
172
|
-
# @param recipient [String]
|
|
173
|
-
# @return [Hash]
|
|
174
|
-
def fetch_detail(cookie, id, recipient)
|
|
175
|
-
raw = { "id" => id, "to" => recipient }
|
|
176
|
-
detail_url = "#{BASE_URL}/en/message/#{id}/html"
|
|
177
|
-
resp = Http.get(
|
|
178
|
-
detail_url,
|
|
179
|
-
headers: BROWSER_HEADERS.merge(
|
|
180
|
-
"Referer" => "#{BASE_URL}/en/inbox",
|
|
181
|
-
"Cookie" => cookie
|
|
182
|
-
),
|
|
183
|
-
timeout: 15
|
|
184
|
-
)
|
|
185
|
-
return raw unless resp.status_code == 200
|
|
186
|
-
|
|
187
|
-
page = resp.body
|
|
188
|
-
|
|
189
|
-
if (m = page.match(DETAIL_FROM_RE))
|
|
190
|
-
raw["from"] = strip_tags(CGI.unescapeHTML(m[1])).strip
|
|
191
|
-
end
|
|
192
|
-
if (m = page.match(DETAIL_SUBJECT_RE))
|
|
193
|
-
raw["subject"] = CGI.unescapeHTML(strip_tags(m[1])).strip
|
|
194
|
-
end
|
|
195
|
-
if (m = page.match(DETAIL_DATE_RE))
|
|
196
|
-
raw["date"] = CGI.unescapeHTML(strip_tags(m[1])).strip
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
body_html = extract_body_html(page)
|
|
200
|
-
raw["html"] = body_html unless body_html.empty?
|
|
201
|
-
|
|
202
|
-
raw
|
|
203
|
-
rescue StandardError
|
|
204
|
-
raw
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module TempmailSdk
|
|
4
|
-
module Providers
|
|
5
|
-
# Temp-Mail.Now 渠道 — https://temp-mail.now
|
|
6
|
-
# 基于会话 Cookie 的临时邮箱服务
|
|
7
|
-
module TempMailNow
|
|
8
|
-
CHANNEL = "temp-mail-now"
|
|
9
|
-
BASE_URL = "https://temp-mail.now"
|
|
10
|
-
|
|
11
|
-
PAGE_HEADERS = {
|
|
12
|
-
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
13
|
-
"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
14
|
-
}.freeze
|
|
15
|
-
|
|
16
|
-
API_HEADERS = {
|
|
17
|
-
"Accept" => "application/json, text/javascript, */*; q=0.01",
|
|
18
|
-
"X-Requested-With" => "XMLHttpRequest",
|
|
19
|
-
"Referer" => "#{BASE_URL}/en/",
|
|
20
|
-
"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
21
|
-
}.freeze
|
|
22
|
-
|
|
23
|
-
module_function
|
|
24
|
-
|
|
25
|
-
def extract_cookies(resp)
|
|
26
|
-
cookies = {}
|
|
27
|
-
resp.set_cookies.each do |line|
|
|
28
|
-
pair = line.split(";").first.to_s.strip
|
|
29
|
-
k, v = pair.split("=", 2)
|
|
30
|
-
cookies[k] = v if k && v
|
|
31
|
-
end
|
|
32
|
-
cookies
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def cookies_to_str(cookies)
|
|
36
|
-
cookies.map { |k, v| "#{k}=#{v}" }.join("; ")
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# 创建临时邮箱
|
|
40
|
-
# @return [EmailInfo]
|
|
41
|
-
def generate_email
|
|
42
|
-
# 获取 session cookie
|
|
43
|
-
resp = Http.get("#{BASE_URL}/en/", headers: PAGE_HEADERS, timeout: 15)
|
|
44
|
-
resp.raise_for_status
|
|
45
|
-
cookies = extract_cookies(resp)
|
|
46
|
-
cookie_str = cookies_to_str(cookies)
|
|
47
|
-
raise "temp-mail-now: 无法获取 session cookie" if cookie_str.empty?
|
|
48
|
-
|
|
49
|
-
# 创建新邮箱
|
|
50
|
-
resp2 = Http.post("#{BASE_URL}/change_email",
|
|
51
|
-
headers: API_HEADERS.merge("Cookie" => cookie_str), timeout: 15)
|
|
52
|
-
resp2.raise_for_status
|
|
53
|
-
|
|
54
|
-
# 合并可能更新的 cookie
|
|
55
|
-
extract_cookies(resp2).each { |k, v| cookies[k] = v }
|
|
56
|
-
cookie_str = cookies_to_str(cookies)
|
|
57
|
-
|
|
58
|
-
data = resp2.json
|
|
59
|
-
raise "temp-mail-now: 响应格式无效" unless data.is_a?(Hash)
|
|
60
|
-
|
|
61
|
-
address = data["new_email"] || ""
|
|
62
|
-
raise "temp-mail-now: 创建邮箱失败" if address.empty? || !address.include?("@")
|
|
63
|
-
|
|
64
|
-
EmailInfo.new(channel: CHANNEL, email: address, token: cookie_str)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# 获取邮件列表
|
|
68
|
-
# @param token [String] session cookie
|
|
69
|
-
# @param email [String]
|
|
70
|
-
# @return [Array<Email>]
|
|
71
|
-
def get_emails(token, email)
|
|
72
|
-
raise "temp-mail-now: session cookie 不能为空" if token.nil? || token.empty?
|
|
73
|
-
|
|
74
|
-
addr = (email || "").strip
|
|
75
|
-
raise "temp-mail-now: 邮箱地址不能为空" if addr.empty?
|
|
76
|
-
|
|
77
|
-
resp = Http.get("#{BASE_URL}/fetch_emails",
|
|
78
|
-
headers: API_HEADERS.merge("Cookie" => token), timeout: 15)
|
|
79
|
-
resp.raise_for_status
|
|
80
|
-
data = resp.json
|
|
81
|
-
return [] unless data.is_a?(Hash)
|
|
82
|
-
|
|
83
|
-
emails_list = data["emails"]
|
|
84
|
-
return [] unless emails_list.is_a?(Array)
|
|
85
|
-
|
|
86
|
-
emails_list.filter_map do |item|
|
|
87
|
-
next unless item.is_a?(Hash)
|
|
88
|
-
|
|
89
|
-
raw = {
|
|
90
|
-
"id" => item["id"] || "",
|
|
91
|
-
"from" => item["from"] || item["from_address"] || item["sender"] || "",
|
|
92
|
-
"to" => item["to"] || addr,
|
|
93
|
-
"subject" => item["subject"] || "",
|
|
94
|
-
"text" => item["text"] || item["body_text"] || "",
|
|
95
|
-
"html" => item["html"] || item["body_html"] || "",
|
|
96
|
-
"date" => item["date"] || item["received_at"] || ""
|
|
97
|
-
}
|
|
98
|
-
Normalize.normalize_email(raw, addr)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "base64"
|
|
4
|
-
require "json"
|
|
5
|
-
require "uri"
|
|
6
|
-
|
|
7
|
-
module TempmailSdk
|
|
8
|
-
module Providers
|
|
9
|
-
# webmailtemp.com 临时邮箱渠道
|
|
10
|
-
# GET /api/create 创建邮箱
|
|
11
|
-
# GET /api/check/{username} 获取邮件列表
|
|
12
|
-
module Webmailtemp
|
|
13
|
-
CHANNEL = "webmailtemp"
|
|
14
|
-
BASE_URL = "https://webmailtemp.com"
|
|
15
|
-
TOK_PREFIX = "wmt1:"
|
|
16
|
-
|
|
17
|
-
HEADERS = {
|
|
18
|
-
"Accept" => "application/json",
|
|
19
|
-
"User-Agent" => "Mozilla/5.0"
|
|
20
|
-
}.freeze
|
|
21
|
-
|
|
22
|
-
module_function
|
|
23
|
-
|
|
24
|
-
def encode_token(username, cookie_hdr)
|
|
25
|
-
raw = JSON.generate({ "u" => username, "c" => cookie_hdr })
|
|
26
|
-
"#{TOK_PREFIX}#{Base64.strict_encode64(raw)}"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def decode_token(token)
|
|
30
|
-
raise "webmailtemp: 无效的 token" unless token&.start_with?(TOK_PREFIX)
|
|
31
|
-
|
|
32
|
-
data = JSON.parse(Base64.decode64(token[TOK_PREFIX.length..]))
|
|
33
|
-
username = (data["u"] || "").strip
|
|
34
|
-
cookie_hdr = (data["c"] || "").strip
|
|
35
|
-
raise "webmailtemp: token 数据无效" if username.empty? || cookie_hdr.empty?
|
|
36
|
-
|
|
37
|
-
{ "username" => username, "cookie" => cookie_hdr }
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# @return [EmailInfo]
|
|
41
|
-
def generate_email
|
|
42
|
-
resp = Http.get("#{BASE_URL}/api/create", headers: HEADERS, timeout: 15)
|
|
43
|
-
resp.raise_for_status
|
|
44
|
-
data = resp.json
|
|
45
|
-
raise "webmailtemp: 创建邮箱响应无效" unless data.is_a?(Hash)
|
|
46
|
-
|
|
47
|
-
email = (data["email"] || "").strip
|
|
48
|
-
username = (data["username"] || "").strip
|
|
49
|
-
|
|
50
|
-
# 从 set_cookies 提取第一个 cookie
|
|
51
|
-
cookie_hdr = ""
|
|
52
|
-
cookies = resp.set_cookies
|
|
53
|
-
unless cookies.empty?
|
|
54
|
-
pair = cookies.first.split(";").first.to_s.strip
|
|
55
|
-
cookie_hdr = pair unless pair.empty?
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
unless data["success"] && !email.empty? && email.include?("@") && !username.empty? && !cookie_hdr.empty?
|
|
59
|
-
raise "webmailtemp: 创建邮箱响应无效"
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
expires_at = nil
|
|
63
|
-
ttl = data["ttl"]
|
|
64
|
-
if ttl.is_a?(Numeric) && ttl > 0
|
|
65
|
-
expires_at = ((Time.now.to_f + ttl) * 1000).to_i
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
EmailInfo.new(channel: CHANNEL, email: email, token: encode_token(username, cookie_hdr),
|
|
69
|
-
expires_at: expires_at)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# @param token [String]
|
|
73
|
-
# @param email [String]
|
|
74
|
-
# @return [Array<Email>]
|
|
75
|
-
def get_emails(token, email)
|
|
76
|
-
address = (email || "").strip
|
|
77
|
-
raise "webmailtemp: 邮箱地址为空" if address.empty?
|
|
78
|
-
|
|
79
|
-
session = decode_token((token || "").strip)
|
|
80
|
-
headers = HEADERS.merge("Cookie" => session["cookie"])
|
|
81
|
-
|
|
82
|
-
resp = Http.get("#{BASE_URL}/api/check/#{URI.encode_www_form_component(session["username"])}",
|
|
83
|
-
headers: headers, timeout: 15)
|
|
84
|
-
resp.raise_for_status
|
|
85
|
-
data = resp.json
|
|
86
|
-
|
|
87
|
-
rows = data.is_a?(Hash) ? data["emails"] : nil
|
|
88
|
-
return [] unless rows.is_a?(Array)
|
|
89
|
-
|
|
90
|
-
rows.filter_map do |row|
|
|
91
|
-
next unless row.is_a?(Hash)
|
|
92
|
-
|
|
93
|
-
raw = {
|
|
94
|
-
"id" => row["id"],
|
|
95
|
-
"from" => row["from"],
|
|
96
|
-
"to" => address,
|
|
97
|
-
"subject" => row["subject"],
|
|
98
|
-
"text" => row["body"],
|
|
99
|
-
"html" => row["html"],
|
|
100
|
-
"date" => row["received_at"] || row["timestamp"],
|
|
101
|
-
"attachments" => row["attachments"]
|
|
102
|
-
}
|
|
103
|
-
Normalize.normalize_email(raw, address)
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|