Initial 423down proxy service
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
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), "个人中心")
|
||||
}
|
||||
Reference in New Issue
Block a user