initial commit
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
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 }
|
||||
Reference in New Issue
Block a user