mirror of
https://github.com/zedeus/nitter.git
synced 2024-06-02 13:12:11 +00:00
apply review feedback
This commit is contained in:
parent
5bd4e545ce
commit
08604ac8d1
|
@ -26,18 +26,14 @@ enableRSS = true # set this to false to disable RSS feeds
|
||||||
enableDebug = false # enable request logs and debug endpoints (/.accounts)
|
enableDebug = false # enable request logs and debug endpoints (/.accounts)
|
||||||
proxy = "" # http/https url, SOCKS proxies are not supported
|
proxy = "" # http/https url, SOCKS proxies are not supported
|
||||||
proxyAuth = ""
|
proxyAuth = ""
|
||||||
tokenCount = 10
|
|
||||||
# minimum amount of usable tokens. tokens are used to authorize API requests,
|
|
||||||
# but they expire after ~1 hour, and have a limit of 500 requests per endpoint.
|
|
||||||
# the limits reset every 15 minutes, and the pool is filled up so there's
|
|
||||||
# always at least `tokenCount` usable tokens. only increase this if you receive
|
|
||||||
# major bursts all the time and don't have a rate limiting setup via e.g. nginx
|
|
||||||
|
|
||||||
# Instead of guest_accounts.json, fetch guest accounts from an external URL.
|
# Instead of guest_accounts.json, fetch guest accounts from an external URL.
|
||||||
# Nitter will re-fetch accounts if it runs out of valid ones.
|
# Nitter will re-fetch accounts if it runs out of valid ones.
|
||||||
guestAccountsUrl = "" # https://example.com/download
|
[GuestAccounts]
|
||||||
guestAccountsHost = "" # defaults to nitter's hostname
|
usePool = false # enable fetching accounts from external pool.
|
||||||
guestAccountsKey = "" # a random string that will be used as a secret to authenticate against the URL
|
poolUrl = "" # https://example.com/download
|
||||||
|
poolId = "" # defaults to nitter's hostname
|
||||||
|
poolAuth = "" # random secret string for authentication
|
||||||
|
|
||||||
# Change default preferences here, see src/prefs_impl.nim for a complete list
|
# Change default preferences here, see src/prefs_impl.nim for a complete list
|
||||||
[Preferences]
|
[Preferences]
|
||||||
|
|
66
src/auth.nim
66
src/auth.nim
|
@ -25,11 +25,6 @@ const
|
||||||
}.toTable
|
}.toTable
|
||||||
|
|
||||||
var
|
var
|
||||||
pool: HttpPool
|
|
||||||
guestAccountsUrl = ""
|
|
||||||
guestAccountsHost = ""
|
|
||||||
guestAccountsKey = ""
|
|
||||||
guestAccountsUrlLastFetched = 0
|
|
||||||
accountPool: seq[GuestAccount]
|
accountPool: seq[GuestAccount]
|
||||||
enableLogging = false
|
enableLogging = false
|
||||||
|
|
||||||
|
@ -164,27 +159,6 @@ proc release*(account: GuestAccount) =
|
||||||
dec account.pending
|
dec account.pending
|
||||||
|
|
||||||
proc getGuestAccount*(api: Api): Future[GuestAccount] {.async.} =
|
proc getGuestAccount*(api: Api): Future[GuestAccount] {.async.} =
|
||||||
let now = epochTime().int
|
|
||||||
|
|
||||||
if accountPool.len == 0 and guestAccountsUrl != "" and guestAccountsUrlLastFetched < now - 3600:
|
|
||||||
once:
|
|
||||||
pool = HttpPool()
|
|
||||||
|
|
||||||
guestAccountsUrlLastFetched = now
|
|
||||||
|
|
||||||
log "fetching more accounts from service"
|
|
||||||
pool.use(newHttpHeaders()):
|
|
||||||
let resp = await c.get("$1?host=$2&key=$3" % [guestAccountsUrl, guestAccountsHost, guestAccountsKey])
|
|
||||||
let guestAccounts = await resp.body
|
|
||||||
|
|
||||||
log "status code from service: ", resp.status
|
|
||||||
|
|
||||||
for line in guestAccounts.splitLines:
|
|
||||||
if line != "":
|
|
||||||
accountPool.add parseGuestAccount(line)
|
|
||||||
|
|
||||||
accountPool.keepItIf(not it.hasExpired)
|
|
||||||
|
|
||||||
for i in 0 ..< accountPool.len:
|
for i in 0 ..< accountPool.len:
|
||||||
if result.isReady(api): break
|
if result.isReady(api): break
|
||||||
result = accountPool.sample()
|
result = accountPool.sample()
|
||||||
|
@ -214,9 +188,6 @@ proc setRateLimit*(account: GuestAccount; api: Api; remaining, reset: int) =
|
||||||
|
|
||||||
proc initAccountPool*(cfg: Config; path: string) =
|
proc initAccountPool*(cfg: Config; path: string) =
|
||||||
enableLogging = cfg.enableDebug
|
enableLogging = cfg.enableDebug
|
||||||
guestAccountsUrl = cfg.guestAccountsUrl
|
|
||||||
guestAccountsHost = cfg.guestAccountsHost
|
|
||||||
guestAccountsKey = cfg.guestAccountsKey
|
|
||||||
|
|
||||||
let jsonlPath = if path.endsWith(".json"): (path & 'l') else: path
|
let jsonlPath = if path.endsWith(".json"): (path & 'l') else: path
|
||||||
|
|
||||||
|
@ -227,20 +198,45 @@ proc initAccountPool*(cfg: Config; path: string) =
|
||||||
elif fileExists(path):
|
elif fileExists(path):
|
||||||
log "Parsing JSON guest accounts file: ", path
|
log "Parsing JSON guest accounts file: ", path
|
||||||
accountPool = parseGuestAccounts(path)
|
accountPool = parseGuestAccounts(path)
|
||||||
elif guestAccountsUrl == "":
|
elif not cfg.guestAccountsUsePool:
|
||||||
echo "[accounts] ERROR: ", path, " not found. This file is required to authenticate API requests."
|
echo "[accounts] ERROR: ", path, " not found. This file is required to authenticate API requests. Alternatively, configure the guest account pool in nitter.conf"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
let accountsPrePurge = accountPool.len
|
|
||||||
accountPool.keepItIf(not it.hasExpired)
|
accountPool.keepItIf(not it.hasExpired)
|
||||||
|
|
||||||
log "Successfully added ", accountPool.len, " valid accounts."
|
log "Successfully added ", accountPool.len, " valid accounts."
|
||||||
|
|
||||||
|
proc updateAccountPool*(cfg: Config) {.async.} =
|
||||||
|
if not cfg.guestAccountsUsePool:
|
||||||
|
return
|
||||||
|
|
||||||
|
while true:
|
||||||
|
if accountPool.len == 0:
|
||||||
|
let pool = HttpPool()
|
||||||
|
|
||||||
|
log "fetching more accounts from service"
|
||||||
|
pool.use(newHttpHeaders()):
|
||||||
|
let resp = await c.get("$1?host=$2&key=$3" % [cfg.guestAccountsPoolUrl, cfg.guestAccountsPoolId, cfg.guestAccountsPoolAuth])
|
||||||
|
let guestAccounts = await resp.body
|
||||||
|
|
||||||
|
log "status code from service: ", resp.status
|
||||||
|
|
||||||
|
for line in guestAccounts.splitLines:
|
||||||
|
if line != "":
|
||||||
|
accountPool.add parseGuestAccount(line)
|
||||||
|
|
||||||
|
accountPool.keepItIf(not it.hasExpired)
|
||||||
|
|
||||||
|
await sleepAsync(3600)
|
||||||
|
|
||||||
proc getAuthHash*(cfg: Config): string =
|
proc getAuthHash*(cfg: Config): string =
|
||||||
if cfg.guestAccountsKey == "":
|
if cfg.guestAccountsPoolAuth == "":
|
||||||
log "guestAccountsKey is set to bogus value, responding with empty string"
|
# If somebody turns on pool auth and provides a dummy key, we should
|
||||||
|
# prevent third parties from using that mis-configured auth and impersonate
|
||||||
|
# this instance
|
||||||
|
log "poolAuth is set to bogus value, responding with empty string"
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
let hashStr = $sha_256.digest(cfg.guestAccountsKey)
|
let hashStr = $sha_256.digest(cfg.guestAccountsPoolAuth)
|
||||||
|
|
||||||
return hashStr.toLowerAscii
|
return hashStr.toLowerAscii
|
||||||
|
|
|
@ -36,14 +36,16 @@ proc getConfig*(path: string): (Config, parseCfg.Config) =
|
||||||
# Config
|
# Config
|
||||||
hmacKey: cfg.get("Config", "hmacKey", "secretkey"),
|
hmacKey: cfg.get("Config", "hmacKey", "secretkey"),
|
||||||
base64Media: cfg.get("Config", "base64Media", false),
|
base64Media: cfg.get("Config", "base64Media", false),
|
||||||
minTokens: cfg.get("Config", "tokenCount", 10),
|
|
||||||
enableRss: cfg.get("Config", "enableRSS", true),
|
enableRss: cfg.get("Config", "enableRSS", true),
|
||||||
enableDebug: cfg.get("Config", "enableDebug", false),
|
enableDebug: cfg.get("Config", "enableDebug", false),
|
||||||
proxy: cfg.get("Config", "proxy", ""),
|
proxy: cfg.get("Config", "proxy", ""),
|
||||||
proxyAuth: cfg.get("Config", "proxyAuth", ""),
|
proxyAuth: cfg.get("Config", "proxyAuth", ""),
|
||||||
guestAccountsUrl: cfg.get("Config", "guestAccountsUrl", ""),
|
|
||||||
guestAccountsKey: cfg.get("Config", "guestAccountsKey", ""),
|
# GuestAccounts
|
||||||
guestAccountsHost: cfg.get("Config", "guestAccountsHost", cfg.get("Server", "hostname", ""))
|
guestAccountsUsePool: cfg.get("GuestAccounts", "usePool", false),
|
||||||
|
guestAccountsPoolUrl: cfg.get("GuestAccounts", "poolUrl", ""),
|
||||||
|
guestAccountsPoolAuth: cfg.get("GuestAccounts", "poolAuth", ""),
|
||||||
|
guestAccountsPoolId: cfg.get("GuestAccounts", "poolId", cfg.get("Server", "hostname", ""))
|
||||||
)
|
)
|
||||||
|
|
||||||
return (conf, cfg)
|
return (conf, cfg)
|
||||||
|
|
|
@ -22,6 +22,7 @@ let
|
||||||
accountsPath = getEnv("NITTER_ACCOUNTS_FILE", "./guest_accounts.json")
|
accountsPath = getEnv("NITTER_ACCOUNTS_FILE", "./guest_accounts.json")
|
||||||
|
|
||||||
initAccountPool(cfg, accountsPath)
|
initAccountPool(cfg, accountsPath)
|
||||||
|
asyncCheck updateAccountPool(cfg)
|
||||||
|
|
||||||
if not cfg.enableDebug:
|
if not cfg.enableDebug:
|
||||||
# Silence Jester's query warning
|
# Silence Jester's query warning
|
||||||
|
|
|
@ -7,6 +7,6 @@ import ".."/[types, auth]
|
||||||
|
|
||||||
proc createAuthRouter*(cfg: Config) =
|
proc createAuthRouter*(cfg: Config) =
|
||||||
router auth:
|
router auth:
|
||||||
get "/.well-known/nitter-auth-sha256":
|
get "/.well-known/nitter-request-auth":
|
||||||
cond cfg.guestAccountsUrl != ""
|
cond cfg.guestAccountsUsePool
|
||||||
resp Http200, {"content-type": "text/plain"}, getAuthHash(cfg)
|
resp Http200, {"content-type": "text/plain"}, getAuthHash(cfg)
|
||||||
|
|
|
@ -254,18 +254,19 @@ type
|
||||||
title*: string
|
title*: string
|
||||||
hostname*: string
|
hostname*: string
|
||||||
staticDir*: string
|
staticDir*: string
|
||||||
guestAccountsUrl*: string
|
|
||||||
guestAccountsKey*: string
|
|
||||||
guestAccountsHost*: string
|
|
||||||
|
|
||||||
hmacKey*: string
|
hmacKey*: string
|
||||||
base64Media*: bool
|
base64Media*: bool
|
||||||
minTokens*: int
|
|
||||||
enableRss*: bool
|
enableRss*: bool
|
||||||
enableDebug*: bool
|
enableDebug*: bool
|
||||||
proxy*: string
|
proxy*: string
|
||||||
proxyAuth*: string
|
proxyAuth*: string
|
||||||
|
|
||||||
|
guestAccountsUsePool*: bool
|
||||||
|
guestAccountsPoolUrl*: string
|
||||||
|
guestAccountsPoolId*: string
|
||||||
|
guestAccountsPoolAuth*: string
|
||||||
|
|
||||||
rssCacheTime*: int
|
rssCacheTime*: int
|
||||||
listCacheTime*: int
|
listCacheTime*: int
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue