From f89d2329d28c802e88747f7beb28db3b7e90cc5d Mon Sep 17 00:00:00 2001 From: Zed Date: Sat, 15 Nov 2025 22:59:35 +0100 Subject: [PATCH] Add cookie-based authentication support Fixes #1303 --- src/apiutils.nim | 28 ++++++++++++++++++++------- src/experimental/parser/session.nim | 30 ++++++++++++++++++++--------- src/experimental/types/session.nim | 3 +++ src/types.nim | 13 +++++++++++-- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/apiutils.nim b/src/apiutils.nim index 65dcc29..875fcb0 100644 --- a/src/apiutils.nim +++ b/src/apiutils.nim @@ -28,12 +28,12 @@ proc getOauthHeader(url, oauthToken, oauthTokenSecret: string): string = return getOauth1RequestHeader(params)["authorization"] -proc genHeaders*(url, oauthToken, oauthTokenSecret: string): HttpHeaders = - let header = getOauthHeader(url, oauthToken, oauthTokenSecret) +proc getCookieHeader(authToken, ct0: string): string = + "auth_token=" & authToken & "; ct0=" & ct0 +proc genHeaders*(session: Session, url: string): HttpHeaders = result = newHttpHeaders({ "connection": "keep-alive", - "authorization": header, "content-type": "application/json", "x-twitter-active-user": "yes", "authority": "api.x.com", @@ -43,18 +43,32 @@ proc genHeaders*(url, oauthToken, oauthTokenSecret: string): HttpHeaders = "DNT": "1" }) + case session.kind + of SessionKind.oauth: + result["authorization"] = getOauthHeader(url, session.oauthToken, session.oauthSecret) + of SessionKind.cookie: + result["cookie"] = getCookieHeader(session.authToken, session.ct0) + result["x-csrf-token"] = session.ct0 + result["x-twitter-auth-type"] = "OAuth2Session" + template fetchImpl(result, fetchBody) {.dirty.} = once: pool = HttpPool() var session = await getSession(api) - if session.oauthToken.len == 0: - echo "[sessions] Empty oauth token, session: ", session.id - raise rateLimitError() + case session.kind + of SessionKind.oauth: + if session.oauthToken.len == 0: + echo "[sessions] Empty oauth token, session: ", session.id + raise rateLimitError() + of SessionKind.cookie: + if session.authToken.len == 0 or session.ct0.len == 0: + echo "[sessions] Empty cookie credentials, session: ", session.id + raise rateLimitError() try: var resp: AsyncResponse - pool.use(genHeaders($url, session.oauthToken, session.oauthSecret)): + pool.use(genHeaders(session, $url)): template getContent = resp = await c.get($url) result = await resp.body diff --git a/src/experimental/parser/session.nim b/src/experimental/parser/session.nim index ee9c93e..db72e85 100644 --- a/src/experimental/parser/session.nim +++ b/src/experimental/parser/session.nim @@ -1,15 +1,27 @@ import std/strutils import jsony import ../types/session -from ../../types import Session +from ../../types import Session, SessionKind proc parseSession*(raw: string): Session = - let - session = raw.fromJson(RawSession) - id = session.oauthToken[0 ..< session.oauthToken.find('-')] + let session = raw.fromJson(RawSession) + let kind = if session.kind == "": "oauth" else: session.kind - result = Session( - id: parseBiggestInt(id), - oauthToken: session.oauthToken, - oauthSecret: session.oauthTokenSecret - ) + case kind + of "oauth": + let id = session.oauthToken[0 ..< session.oauthToken.find('-')] + result = Session( + kind: SessionKind.oauth, + id: parseBiggestInt(id), + oauthToken: session.oauthToken, + oauthSecret: session.oauthTokenSecret + ) + of "cookie": + result = Session( + kind: SessionKind.cookie, + id: 999, + authToken: session.authToken, + ct0: session.ct0 + ) + else: + raise newException(ValueError, "Unknown session kind: " & kind) diff --git a/src/experimental/types/session.nim b/src/experimental/types/session.nim index 4165204..c0cb58f 100644 --- a/src/experimental/types/session.nim +++ b/src/experimental/types/session.nim @@ -1,4 +1,7 @@ type RawSession* = object + kind*: string oauthToken*: string oauthTokenSecret*: string + authToken*: string + ct0*: string diff --git a/src/types.nim b/src/types.nim index 4e565ee..5755f65 100644 --- a/src/types.nim +++ b/src/types.nim @@ -31,14 +31,23 @@ type remaining*: int reset*: int + SessionKind* = enum + oauth + cookie + Session* = ref object id*: int64 - oauthToken*: string - oauthSecret*: string pending*: int limited*: bool limitedAt*: int apis*: Table[Api, RateLimit] + case kind*: SessionKind + of oauth: + oauthToken*: string + oauthSecret*: string + of cookie: + authToken*: string + ct0*: string Error* = enum null = 0