123 lines
2.9 KiB
Go
123 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
|
|
"resty.dev/v3"
|
|
)
|
|
|
|
type loginCredentials struct {
|
|
user string
|
|
password string
|
|
}
|
|
|
|
// getLoginCookies 优先读取数据库中的 Cookie,未命中时执行登录并缓存新 Cookie。
|
|
func getLoginCookies(db *DB, client *resty.Client) ([]*http.Cookie, error) {
|
|
cookies, err := db.GetCookie()
|
|
if err == nil {
|
|
return cookies, nil
|
|
}
|
|
if !errors.Is(err, errCookieNotFound) {
|
|
return nil, err
|
|
}
|
|
|
|
credentials, err := loadLoginCredentials()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cookies, err = login423Down(client, credentials)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(cookies) == 0 {
|
|
return cookies, nil
|
|
}
|
|
|
|
if err := db.SetCookie(cookies); err != nil {
|
|
slog.Warn("failed to cache login cookies", slog.String("error", err.Error()))
|
|
}
|
|
|
|
return cookies, nil
|
|
}
|
|
|
|
// loadLoginCredentials 从环境变量读取 423down 登录账号。
|
|
func loadLoginCredentials() (loginCredentials, error) {
|
|
credentials := loginCredentials{
|
|
user: strings.TrimSpace(os.Getenv(loginUserEnv)),
|
|
password: os.Getenv(loginPasswordEnv),
|
|
}
|
|
if credentials.user == "" || credentials.password == "" {
|
|
return loginCredentials{}, fmt.Errorf("missing login credentials: set %s and %s", loginUserEnv, loginPasswordEnv)
|
|
}
|
|
|
|
return credentials, nil
|
|
}
|
|
|
|
// login423Down 提交 WordPress 登录表单并返回登录态 Cookie。
|
|
func login423Down(client *resty.Client, credentials loginCredentials) ([]*http.Cookie, error) {
|
|
form := url.Values{}
|
|
form.Add("log", credentials.user)
|
|
form.Add("pwd", credentials.password)
|
|
form.Add("rememberme", "forever")
|
|
form.Add("wp-submit", "登录")
|
|
form.Add("testcookie", "1")
|
|
|
|
resp, err := client.R().
|
|
SetHeader("Content-Type", "application/x-www-form-urlencoded").
|
|
SetBody(form.Encode()).
|
|
Post(loginURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("login request failed: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
cookies := resp.Cookies()
|
|
if hasWordPressLoggedInCookie(cookies) {
|
|
return cookies, nil
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read login response failed: %w", err)
|
|
}
|
|
if canVisitLimitedPage(body) {
|
|
return cookies, nil
|
|
}
|
|
|
|
return nil, errors.New("failed to get login cookies")
|
|
}
|
|
|
|
// hasWordPressLoggedInCookie 判断响应中是否包含 WordPress 登录态 Cookie。
|
|
func hasWordPressLoggedInCookie(cookies []*http.Cookie) bool {
|
|
for _, cookie := range cookies {
|
|
if strings.Contains(cookie.Name, "wordpress_logged_in") {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// canVisitLimitedPage 兼容源站可能返回明文或 base64 编码页面的情况。
|
|
func canVisitLimitedPage(body []byte) bool {
|
|
if strings.Contains(string(body), "个人中心") {
|
|
return true
|
|
}
|
|
|
|
decoded, err := base64.StdEncoding.DecodeString(string(body))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return strings.Contains(string(decoded), "个人中心")
|
|
}
|