FILE / ScuroNeko/go-deepseek
auth.go
Исходный файл и его история в репозитории.
125 lines
2.9 KiB
Go
125 lines
2.9 KiB
Go
package deepseek
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// DeviceIDFromJar returns the base64-encoded value of the first DeepSeek
|
|
// thumbcache cookie in jar.
|
|
func (api *Client) DeviceIDFromJar(jar http.CookieJar) (string, error) {
|
|
if jar == nil {
|
|
return "", errors.New("cookie jar is nil")
|
|
}
|
|
|
|
u, err := url.Parse("https://chat.deepseek.com")
|
|
if err != nil {
|
|
return "", fmt.Errorf("parse DeepSeek URL: %w", err)
|
|
}
|
|
|
|
for _, cookie := range jar.Cookies(u) {
|
|
if strings.HasPrefix(cookie.Name, ".thumbcache_") {
|
|
if cookie.Value == "" {
|
|
return "", errors.New("thumbcache cookie is empty")
|
|
}
|
|
|
|
deviceID := base64.StdEncoding.EncodeToString(
|
|
[]byte(cookie.Value),
|
|
)
|
|
|
|
return deviceID, nil
|
|
}
|
|
}
|
|
|
|
return "", errors.New("thumbcache cookie not found")
|
|
}
|
|
|
|
// LoginReq is the request body used to authenticate a user.
|
|
type LoginReq struct {
|
|
DeviceID string `json:"device_id"`
|
|
OS string `json:"os"`
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
// LoginRes contains the user returned by a successful login.
|
|
type LoginRes struct {
|
|
User User `json:"user"`
|
|
}
|
|
|
|
// User describes an authenticated DeepSeek user.
|
|
type User struct {
|
|
ID string `json:"id"`
|
|
Token string `json:"token"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
// Login authenticates with email and password and stores the returned bearer
|
|
// token on api. It uses a random device ID when no provider is configured.
|
|
func (api *Client) Login(email, password string) error {
|
|
var deviceID string
|
|
var err error
|
|
if api.deviceIDProvider != nil {
|
|
deviceID, err = api.deviceIDProvider.Get()
|
|
} else {
|
|
deviceID, err = RandomDeviceIDProvider().Get()
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
body := LoginReq{
|
|
DeviceID: deviceID,
|
|
OS: "ios",
|
|
Email: email,
|
|
Password: password,
|
|
}
|
|
|
|
req := NewRequest[LoginRes]("POST", "users/login", body)
|
|
resp, err := req.Do(api)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
response, err := req.unmarshallBizResponse(resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
api.SetToken(response.Data.Data.User.Token)
|
|
return nil
|
|
}
|
|
|
|
// DeviceIDProvider supplies the device ID sent during login.
|
|
type DeviceIDProvider interface {
|
|
Get() (string, error)
|
|
}
|
|
|
|
type randomDeviceIDProvider struct{}
|
|
|
|
// RandomDeviceIDProvider returns a provider that generates a random device ID
|
|
// for every call to Get.
|
|
func RandomDeviceIDProvider() randomDeviceIDProvider {
|
|
return randomDeviceIDProvider{}
|
|
}
|
|
func (p randomDeviceIDProvider) Get() (string, error) {
|
|
raw := make([]byte, 64)
|
|
if _, err := rand.Read(raw); err != nil {
|
|
return "", err
|
|
}
|
|
return base64.StdEncoding.EncodeToString(raw), nil
|
|
}
|
|
|
|
type staticDeviceIDProvider struct {
|
|
id string
|
|
}
|
|
|
|
// StaticDeviceIDProvider returns a provider that always returns id.
|
|
func StaticDeviceIDProvider(id string) staticDeviceIDProvider {
|
|
return staticDeviceIDProvider{id: id}
|
|
}
|
|
func (p staticDeviceIDProvider) Get() (string, error) { return p.id, nil }
|