Module: TempmailSdk::Providers::Zhujump

Defined in:
lib/tempmail_sdk/providers/zhujump.rb

Overview

mail.zhujump.com 固定域渠道 通过注册账号、登录会话后创建固定域邮箱,再通过邮箱 ID 拉取邮件列表

Defined Under Namespace

Classes: Session

Constant Summary collapse

BASE_URL =
"https://mail.zhujump.com"
TOKEN_PREFIX =
"zhj1:"
DEFAULT_EXPIRY_TIME =
60 * 60 * 1000
HEADERS =
{
  "Accept" => "application/json",
  "Origin" => BASE_URL,
  "Referer" => "#{BASE_URL}/zh-CN/login",
  "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"
}.freeze

Class Method Summary collapse

Class Method Details

.decode_token(token) ⇒ Object

从 token 解码出会话信息



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 50

def decode_token(token)
  raise "zhujump: invalid session token" unless token.to_s.start_with?(TOKEN_PREFIX)

  payload = token[TOKEN_PREFIX.length..]
  data = JSON.parse(Base64.strict_decode64(payload))
  cookie = data["c"].to_s.strip
  email_id = data["i"].to_s.strip
  raise "zhujump: invalid session token" if cookie.empty? || email_id.empty?

  base_url = (data["b"] || BASE_URL).to_s.strip.chomp("/")
  { "cookie" => cookie, "email_id" => email_id, "base_url" => base_url }
rescue ArgumentError, JSON::ParserError => e
  raise "zhujump: invalid session token (#{e.message})"
end

.encode_token(cookie, email_id, base_url) ⇒ Object

将会话信息编码为 token(base64 JSON)



44
45
46
47
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 44

def encode_token(cookie, email_id, base_url)
  raw = JSON.generate({ "c" => cookie, "i" => email_id, "b" => base_url })
  TOKEN_PREFIX + Base64.strict_encode64(raw)
end

.generate_email(domain, channel) ⇒ EmailInfo

Parameters:

  • domain (String)

    邮箱域名

  • channel (String)

    渠道标识

Returns:



146
147
148
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 146

def generate_email(domain, channel)
  generate_email_for_instance(BASE_URL, domain, channel, DEFAULT_EXPIRY_TIME)
end

.generate_email_for_instance(base_url, domain, channel, expiry_time = DEFAULT_EXPIRY_TIME) ⇒ EmailInfo

Parameters:

  • base_url (String)

    实例基础 URL

  • domain (String)

    邮箱域名

  • channel (String)

    渠道标识

  • expiry_time (Integer, nil) (defaults to: DEFAULT_EXPIRY_TIME)

    过期时间(毫秒)

Returns:



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 155

def generate_email_for_instance(base_url, domain, channel, expiry_time = DEFAULT_EXPIRY_TIME)
  base_url = base_url.chomp("/")
  sess = Session.new(base_url)
  username = random_value("sdk", 10)
  password = random_password

  # 注册
  reg = sess.post("/api/auth/register",
                  json: { "username" => username, "password" => password, "turnstileToken" => "" })
  raise "zhujump: register failed (#{reg.code})" unless reg.is_a?(Net::HTTPSuccess)

  # 获取 CSRF
  csrf_resp = sess.get("/api/auth/csrf")
  raise "zhujump: csrf request failed" unless csrf_resp.is_a?(Net::HTTPSuccess)

  csrf_data = JSON.parse(csrf_resp.body || "{}")
  csrf = csrf_data["csrfToken"].to_s.strip
  raise "zhujump: csrf token missing" if csrf.empty?

  # 登录
   = sess.post("/api/auth/callback/credentials?",
                    form: {
                      "username" => username, "password" => password,
                      "turnstileToken" => "", "redirect" => "false",
                      "csrfToken" => csrf, "callbackUrl" => (base_url)
                    },
                    extra_headers: { "x-auth-return-redirect" => "1" })
  # 允许 3xx 重定向也视为成功
  code = .code.to_i
  raise "zhujump: login failed (#{code})" unless code >= 200 && code < 400

  # 验证 session
  session_resp = sess.get("/api/auth/session")
  raise "zhujump: session check failed" unless session_resp.is_a?(Net::HTTPSuccess)

  session_json = JSON.parse(session_resp.body || "{}")
  got_user = (session_json.dig("user", "username") || "").strip
  raise "zhujump: login verification failed" unless got_user == username

  # 创建邮箱
  local = random_value("sdk", 10)
  body = { "name" => local, "domain" => domain }
  body["expiryTime"] = expiry_time unless expiry_time.nil?
  created = sess.post("/api/emails/generate", json: body)
  raise "zhujump: generate email failed (#{created.code})" unless created.is_a?(Net::HTTPSuccess)

  created_json = JSON.parse(created.body || "{}")
  email_addr = created_json["email"].to_s.strip
  email_id = created_json["id"].to_s.strip
  raise "zhujump: invalid generate response" if email_addr.empty? || email_id.empty?

  cookie = sess.cookies.map { |k, v| "#{k}=#{v}" }.join("; ")
  EmailInfo.new(channel: channel, email: email_addr,
                token: encode_token(cookie, email_id, base_url))
end

.get_emails(token, email) ⇒ Array<Email>

Parameters:

  • token (String)

    编码的会话 token

  • email (String)

    邮箱地址

Returns:



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 214

def get_emails(token, email)
  session = decode_token(token)
  base_url = session["base_url"]
  hdrs = make_headers(base_url).merge("Cookie" => session["cookie"])

  resp = Http.get("#{base_url}/api/emails/#{session['email_id']}", headers: hdrs)
  resp.raise_for_status
  data = resp.json
  rows = data.is_a?(Hash) ? data["messages"] : nil
  return [] unless rows.is_a?(Array)

  rows.filter_map do |item|
    next unless item.is_a?(Hash)

    source = item
    message_id = item["id"].to_s.strip
    if !message_id.empty? && item["content"].to_s.strip.empty? && item["html"].to_s.strip.empty?
      begin
        d = Http.get("#{base_url}/api/emails/#{session['email_id']}/#{message_id}", headers: hdrs)
        if d.ok?
          detail_data = d.json
          msg = detail_data.is_a?(Hash) ? detail_data["message"] : nil
          source = item.merge(msg) if msg.is_a?(Hash)
        end
      rescue StandardError
        # 忽略详情失败
      end
    end
    Normalize.normalize_email({
                                "id" => source["id"] || "",
                                "from_address" => source["from_address"] || "",
                                "to_address" => source["to_address"] || email,
                                "subject" => source["subject"] || "",
                                "content" => source["content"] || "",
                                "html" => source["html"] || "",
                                "received_at" => source["received_at"] || source["sent_at"],
                                "isRead" => false
                              }, email)
  end
end

.login_referer(base_url) ⇒ Object



35
36
37
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 35

def (base_url)
  "#{base_url}/zh-CN/login"
end

.make_headers(base_url) ⇒ Object



39
40
41
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 39

def make_headers(base_url)
  HEADERS.merge("Origin" => base_url, "Referer" => (base_url))
end

.random_passwordObject



31
32
33
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 31

def random_password
  "Sdk!#{random_value('', 12)}A1"
end

.random_value(prefix, size) ⇒ Object



26
27
28
29
# File 'lib/tempmail_sdk/providers/zhujump.rb', line 26

def random_value(prefix, size)
  chars = ("a".."z").to_a + ("0".."9").to_a
  "#{prefix}#{Array.new(size) { chars.sample }.join}"
end