File size: 3,463 Bytes
8059bf0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { describe, expect, it } from 'vitest'
import { parseSoraRawTokens } from '@/utils/soraTokenParser'

describe('parseSoraRawTokens', () => {
  it('parses sessionToken and accessToken from JSON payload', () => {
    const payload = JSON.stringify({
      user: { id: 'u1' },
      accessToken: 'at-json-1',
      sessionToken: 'st-json-1'
    })

    const result = parseSoraRawTokens(payload)

    expect(result.sessionTokens).toEqual(['st-json-1'])
    expect(result.accessTokens).toEqual(['at-json-1'])
  })

  it('supports plain session tokens (one per line)', () => {
    const result = parseSoraRawTokens('st-1\nst-2')

    expect(result.sessionTokens).toEqual(['st-1', 'st-2'])
    expect(result.accessTokens).toEqual([])
  })

  it('supports non-standard object snippets via regex', () => {
    const raw = "sessionToken: 'st-snippet', access_token: \"at-snippet\""
    const result = parseSoraRawTokens(raw)

    expect(result.sessionTokens).toEqual(['st-snippet'])
    expect(result.accessTokens).toEqual(['at-snippet'])
  })

  it('keeps unique tokens and extracts JWT-like plain line as AT too', () => {
    const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature'
    const raw = `st-dup\nst-dup\n${jwt}\n${JSON.stringify({ sessionToken: 'st-json', accessToken: jwt })}`
    const result = parseSoraRawTokens(raw)

    expect(result.sessionTokens).toEqual(['st-json', 'st-dup'])
    expect(result.accessTokens).toEqual([jwt])
  })

  it('parses session token from Set-Cookie line and strips cookie attributes', () => {
    const raw =
      '__Secure-next-auth.session-token.0=st-cookie-part-0; Domain=.chatgpt.com; Path=/; Expires=Thu, 28 May 2026 11:43:36 GMT; HttpOnly; Secure; SameSite=Lax'
    const result = parseSoraRawTokens(raw)

    expect(result.sessionTokens).toEqual(['st-cookie-part-0'])
    expect(result.accessTokens).toEqual([])
  })

  it('merges chunked session-token cookies by numeric suffix order', () => {
    const raw = [
      'Set-Cookie: __Secure-next-auth.session-token.1=part-1; Path=/; HttpOnly',
      'Set-Cookie: __Secure-next-auth.session-token.0=part-0; Path=/; HttpOnly'
    ].join('\n')
    const result = parseSoraRawTokens(raw)

    expect(result.sessionTokens).toEqual(['part-0part-1'])
    expect(result.accessTokens).toEqual([])
  })

  it('prefers latest duplicate chunk values when multiple cookie groups exist', () => {
    const raw = [
      'Set-Cookie: __Secure-next-auth.session-token.0=old-0; Path=/; HttpOnly',
      'Set-Cookie: __Secure-next-auth.session-token.1=old-1; Path=/; HttpOnly',
      'Set-Cookie: __Secure-next-auth.session-token.0=new-0; Path=/; HttpOnly',
      'Set-Cookie: __Secure-next-auth.session-token.1=new-1; Path=/; HttpOnly'
    ].join('\n')
    const result = parseSoraRawTokens(raw)

    expect(result.sessionTokens).toEqual(['new-0new-1'])
    expect(result.accessTokens).toEqual([])
  })

  it('uses latest complete chunk group and ignores incomplete latest group', () => {
    const raw = [
      'set-cookie',
      '__Secure-next-auth.session-token.0=ok-0; Domain=.chatgpt.com; Path=/',
      'set-cookie',
      '__Secure-next-auth.session-token.1=ok-1; Domain=.chatgpt.com; Path=/',
      'set-cookie',
      '__Secure-next-auth.session-token.0=partial-0; Domain=.chatgpt.com; Path=/'
    ].join('\n')

    const result = parseSoraRawTokens(raw)

    expect(result.sessionTokens).toEqual(['ok-0ok-1'])
    expect(result.accessTokens).toEqual([])
  })
})