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 }