mirror of
https://github.com/zedeus/nitter.git
synced 2026-01-31 07:42:51 -05:00
Compare commits
7 Commits
693a189462
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a45227b883 | ||
|
|
a92e79ebc3 | ||
|
|
baeaf685d3 | ||
|
|
51b54852dc | ||
|
|
663f5a52e1 | ||
|
|
17fc2628f9 | ||
|
|
e741385828 |
@@ -26,7 +26,9 @@ enableRSS = true # set this to false to disable RSS feeds
|
||||
enableDebug = false # enable request logs and debug endpoints (/.sessions)
|
||||
proxy = "" # http/https url, SOCKS proxies are not supported
|
||||
proxyAuth = ""
|
||||
apiProxy = "" # nitter-proxy host, e.g. localhost:7000
|
||||
disableTid = false # enable this if cookie-based auth is failing
|
||||
maxConcurrentReqs = 2 # max requests at a time per session to avoid race conditions
|
||||
|
||||
# Change default preferences here, see src/prefs_impl.nim for a complete list
|
||||
[Preferences]
|
||||
|
||||
@@ -13,10 +13,17 @@ const
|
||||
var
|
||||
pool: HttpPool
|
||||
disableTid: bool
|
||||
apiProxy: string
|
||||
|
||||
proc setDisableTid*(disable: bool) =
|
||||
disableTid = disable
|
||||
|
||||
proc setApiProxy*(url: string) =
|
||||
if url.len > 0:
|
||||
apiProxy = url.strip(chars={'/'}) & "/"
|
||||
if "http" notin apiProxy:
|
||||
apiProxy = "http://" & apiProxy
|
||||
|
||||
proc toUrl(req: ApiReq; sessionKind: SessionKind): Uri =
|
||||
case sessionKind
|
||||
of oauth:
|
||||
@@ -56,7 +63,8 @@ proc genHeaders*(session: Session, url: Uri): Future[HttpHeaders] {.async.} =
|
||||
"origin": "https://x.com",
|
||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
|
||||
"x-twitter-active-user": "yes",
|
||||
"x-twitter-client-language": "en"
|
||||
"x-twitter-client-language": "en",
|
||||
"priority": "u=1, i"
|
||||
})
|
||||
|
||||
case session.kind
|
||||
@@ -66,6 +74,12 @@ proc genHeaders*(session: Session, url: Uri): Future[HttpHeaders] {.async.} =
|
||||
result["x-twitter-auth-type"] = "OAuth2Session"
|
||||
result["x-csrf-token"] = session.ct0
|
||||
result["cookie"] = getCookieHeader(session.authToken, session.ct0)
|
||||
result["sec-ch-ua"] = """"Google Chrome";v="142", "Chromium";v="142", "Not A(Brand";v="24""""
|
||||
result["sec-ch-ua-mobile"] = "?0"
|
||||
result["sec-ch-ua-platform"] = "Windows"
|
||||
result["sec-fetch-dest"] = "empty"
|
||||
result["sec-fetch-mode"] = "cors"
|
||||
result["sec-fetch-site"] = "same-site"
|
||||
if disableTid:
|
||||
result["authorization"] = bearerToken2
|
||||
else:
|
||||
@@ -92,6 +106,10 @@ template fetchImpl(result, fetchBody) {.dirty.} =
|
||||
var resp: AsyncResponse
|
||||
pool.use(await genHeaders(session, url)):
|
||||
template getContent =
|
||||
# TODO: this is a temporary simple implementation
|
||||
if apiProxy.len > 0:
|
||||
resp = await c.get(($url).replace("https://", apiProxy))
|
||||
else:
|
||||
resp = await c.get($url)
|
||||
result = await resp.body
|
||||
|
||||
|
||||
11
src/auth.nim
11
src/auth.nim
@@ -3,14 +3,17 @@ import std/[asyncdispatch, times, json, random, strutils, tables, packedsets, os
|
||||
import types, consts
|
||||
import experimental/parser/session
|
||||
|
||||
# max requests at a time per session to avoid race conditions
|
||||
const
|
||||
maxConcurrentReqs = 2
|
||||
hourInSeconds = 60 * 60
|
||||
const hourInSeconds = 60 * 60
|
||||
|
||||
var
|
||||
sessionPool: seq[Session]
|
||||
enableLogging = false
|
||||
# max requests at a time per session to avoid race conditions
|
||||
maxConcurrentReqs = 2
|
||||
|
||||
proc setMaxConcurrentReqs*(reqs: int) =
|
||||
if reqs > 0:
|
||||
maxConcurrentReqs = reqs
|
||||
|
||||
template log(str: varargs[string, `$`]) =
|
||||
echo "[sessions] ", str.join("")
|
||||
|
||||
@@ -41,7 +41,9 @@ proc getConfig*(path: string): (Config, parseCfg.Config) =
|
||||
enableDebug: cfg.get("Config", "enableDebug", false),
|
||||
proxy: cfg.get("Config", "proxy", ""),
|
||||
proxyAuth: cfg.get("Config", "proxyAuth", ""),
|
||||
disableTid: cfg.get("Config", "disableTid", false)
|
||||
apiProxy: cfg.get("Config", "apiProxy", ""),
|
||||
disableTid: cfg.get("Config", "disableTid", false),
|
||||
maxConcurrentReqs: cfg.get("Config", "maxConcurrentReqs", 2)
|
||||
)
|
||||
|
||||
return (conf, cfg)
|
||||
|
||||
@@ -37,7 +37,9 @@ setHmacKey(cfg.hmacKey)
|
||||
setProxyEncoding(cfg.base64Media)
|
||||
setMaxHttpConns(cfg.httpMaxConns)
|
||||
setHttpProxy(cfg.proxy, cfg.proxyAuth)
|
||||
setApiProxy(cfg.apiProxy)
|
||||
setDisableTid(cfg.disableTid)
|
||||
setMaxConcurrentReqs(cfg.maxConcurrentReqs)
|
||||
initAboutPage(cfg.staticDir)
|
||||
|
||||
waitFor initRedisPool(cfg)
|
||||
|
||||
@@ -114,7 +114,7 @@ proc createTimelineRouter*(cfg: Config) =
|
||||
get "/@name/?@tab?/?":
|
||||
cond '.' notin @"name"
|
||||
cond @"name" notin ["pic", "gif", "video", "search", "settings", "login", "intent", "i"]
|
||||
cond @"name".allCharsInSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
|
||||
cond @"name".allCharsInSet({'a'..'z', 'A'..'Z', '0'..'9', '_', ','})
|
||||
cond @"tab" in ["with_replies", "media", "search", ""]
|
||||
let
|
||||
prefs = cookiePrefs()
|
||||
|
||||
@@ -275,7 +275,9 @@ type
|
||||
enableDebug*: bool
|
||||
proxy*: string
|
||||
proxyAuth*: string
|
||||
apiProxy*: string
|
||||
disableTid*: bool
|
||||
maxConcurrentReqs*: int
|
||||
|
||||
rssCacheTime*: int
|
||||
listCacheTime*: int
|
||||
|
||||
@@ -26,6 +26,7 @@ proc renderUserCard*(user: User; prefs: Prefs): VNode =
|
||||
|
||||
tdiv(class="profile-card-tabs-name"):
|
||||
linkUser(user, class="profile-card-fullname")
|
||||
verifiedIcon(user)
|
||||
linkUser(user, class="profile-card-username")
|
||||
|
||||
tdiv(class="profile-card-extra"):
|
||||
|
||||
@@ -42,7 +42,6 @@ proc linkUser*(user: User, class=""): VNode =
|
||||
buildHtml(a(href=href, class=class, title=nameText)):
|
||||
text nameText
|
||||
if isName:
|
||||
verifiedIcon(user)
|
||||
if user.protected:
|
||||
text " "
|
||||
icon "lock", title="Protected account"
|
||||
|
||||
@@ -66,6 +66,7 @@ proc renderUser(user: User; prefs: Prefs): VNode =
|
||||
tdiv(class="tweet-name-row"):
|
||||
tdiv(class="fullname-and-username"):
|
||||
linkUser(user, class="fullname")
|
||||
verifiedIcon(user)
|
||||
linkUser(user, class="username")
|
||||
|
||||
tdiv(class="tweet-content media-body", dir="auto"):
|
||||
|
||||
@@ -31,6 +31,7 @@ proc renderHeader(tweet: Tweet; retweet: string; pinned: bool; prefs: Prefs): VN
|
||||
tdiv(class="tweet-name-row"):
|
||||
tdiv(class="fullname-and-username"):
|
||||
linkUser(tweet.user, class="fullname")
|
||||
verifiedIcon(tweet.user)
|
||||
linkUser(tweet.user, class="username")
|
||||
|
||||
span(class="tweet-date"):
|
||||
@@ -235,6 +236,7 @@ proc renderQuote(quote: Tweet; prefs: Prefs; path: string): VNode =
|
||||
tdiv(class="fullname-and-username"):
|
||||
renderMiniAvatar(quote.user, prefs)
|
||||
linkUser(quote.user, class="fullname")
|
||||
verifiedIcon(quote.user)
|
||||
linkUser(quote.user, class="username")
|
||||
|
||||
span(class="tweet-date"):
|
||||
|
||||
@@ -21,7 +21,10 @@ def auth(username, password, otp_secret):
|
||||
|
||||
guest_token = requests.post(
|
||||
"https://api.twitter.com/1.1/guest/activate.json",
|
||||
headers={'Authorization': bearer_token}
|
||||
headers={
|
||||
'Authorization': bearer_token,
|
||||
"User-Agent": "TwitterAndroid/10.21.0-release.0 (310210000-r-0) ONEPLUS+A3010/9"
|
||||
}
|
||||
).json().get('guest_token')
|
||||
|
||||
if not guest_token:
|
||||
|
||||
Reference in New Issue
Block a user