feat: add Ktor and Apollo (GraphQL) API-extraction patterns
The previous find-api-calls.sh covered only Retrofit, OkHttp, and Volley.
Modern Kotlin and KMP apps increasingly ship Ktor as their HTTP client
(used by ~25 % of new Kotlin apps as of 2025), and many product apps use
Apollo Kotlin for GraphQL. Both produced zero hits with the old patterns.
Add two new modes to find-api-calls.sh:
--ktor Ktor client calls (client.get/post/...), HttpRequestBuilder,
defaultRequest blocks, and the Auth bearer DSL
(BearerTokens / loadTokens / refreshTokens)
--apollo ApolloClient, .serverUrl(), HttpNetworkTransport, and
.query/.mutation/.subscription operation calls
Document both in references/api-extraction-patterns.md with example
post-decompile snippets and a note on R8 obfuscation: Ktor call sites
get inlined to obfuscated method calls, but the path string literals
and Ktor library symbols (BearerTokens, URLProtocol, etc.) survive,
so library-internal patterns still work as anchors.
This commit is contained in:
parent
5b63fcb418
commit
371d3d4bed
|
|
@ -55,6 +55,65 @@ grep -rn 'Interceptor\|addInterceptor\|addNetworkInterceptor\|intercept(' source
|
|||
grep -rn '\.execute()\|\.enqueue(' sources/
|
||||
```
|
||||
|
||||
## Ktor (Kotlin)
|
||||
|
||||
Ktor is the dominant HTTP client in Kotlin Multiplatform and modern
|
||||
Kotlin-only Android apps. Unlike Retrofit, Ktor does **not** use annotations
|
||||
to declare endpoints — paths appear as plain string arguments to
|
||||
`client.get(...)` / `client.post(...)`, often inside an extension function.
|
||||
|
||||
```bash
|
||||
# Calls
|
||||
grep -rn '\b\(client\|httpClient\|HttpClient\)\.\(get\|post\|put\|delete\|patch\|head\|request\)\s*[<(]' sources/
|
||||
|
||||
# Default request / base URL configuration
|
||||
grep -rn 'HttpRequestBuilder\|defaultRequest\s*{\|\burl\s*(\s*"\|URLBuilder' sources/
|
||||
|
||||
# Auth plugin (bearer / refresh)
|
||||
grep -rn '\bbearer\s*{\|BearerTokens\s*(\|loadTokens\s*{\|refreshTokens\s*{' sources/
|
||||
```
|
||||
|
||||
Typical Ktor call (after decompile):
|
||||
|
||||
```java
|
||||
client.get("api/v1/users/profile") {
|
||||
parameter("locale", "en-US");
|
||||
}
|
||||
```
|
||||
|
||||
The base URL is usually applied via `defaultRequest { url { host = "..." } }`
|
||||
in the client builder. Search for `host =` and `URLProtocol.HTTPS` references
|
||||
to pin it down.
|
||||
|
||||
**Note on obfuscation:** in heavily R8-shrunk apps the call site
|
||||
`client.get("path")` is inlined to something like `aVar.a(dVar, "path")`
|
||||
and the `client.<verb>(` regex misses it. The path string itself is **not**
|
||||
obfuscated, however — fall back to the generic path-literal search
|
||||
(`--paths`) for the endpoint inventory in those cases. Ktor library
|
||||
internals (`BearerTokens`, `loadTokens`, `refreshTokens`, `URLProtocol`)
|
||||
remain searchable because Ktor keeps these on its public API.
|
||||
|
||||
Ktor's authentication plugin uses the
|
||||
[`Auth { bearer { loadTokens { ... }; refreshTokens { ... } } }`](https://ktor.io/docs/auth.html)
|
||||
DSL — bearer access tokens with automatic refresh. After R8, the DSL
|
||||
lambdas appear as `Function2`/`Function3` impls referencing
|
||||
`BearerTokens(...)` calls.
|
||||
|
||||
## Apollo Kotlin (GraphQL)
|
||||
|
||||
```bash
|
||||
# Client setup
|
||||
grep -rn 'ApolloClient\|\.serverUrl(\|HttpNetworkTransport' sources/
|
||||
|
||||
# Operations (queries / mutations / subscriptions)
|
||||
grep -rn '\.query(\s*[A-Z]\|\.mutation(\s*[A-Z]\|\.subscription(\s*[A-Z]' sources/
|
||||
```
|
||||
|
||||
Apollo generates one class per operation under a generated package; once you
|
||||
find the GraphQL endpoint URL via `ApolloClient.serverUrl("...")`, use the
|
||||
operation classes themselves as the API documentation — each carries its
|
||||
GraphQL document text in `OPERATION_DOCUMENT`.
|
||||
|
||||
## Volley
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ Arguments:
|
|||
Options:
|
||||
--retrofit Search only for Retrofit annotations
|
||||
--okhttp Search only for OkHttp patterns
|
||||
--ktor Search only for Ktor client patterns
|
||||
--apollo Search only for Apollo (GraphQL) patterns
|
||||
--volley Search only for Volley patterns
|
||||
--urls Search only for hardcoded URLs
|
||||
--auth Search only for auth-related patterns
|
||||
|
|
@ -29,6 +31,8 @@ EOF
|
|||
SOURCE_DIR=""
|
||||
SEARCH_RETROFIT=false
|
||||
SEARCH_OKHTTP=false
|
||||
SEARCH_KTOR=false
|
||||
SEARCH_APOLLO=false
|
||||
SEARCH_VOLLEY=false
|
||||
SEARCH_URLS=false
|
||||
SEARCH_AUTH=false
|
||||
|
|
@ -38,6 +42,8 @@ while [[ $# -gt 0 ]]; do
|
|||
case "$1" in
|
||||
--retrofit) SEARCH_RETROFIT=true; SEARCH_ALL=false; shift ;;
|
||||
--okhttp) SEARCH_OKHTTP=true; SEARCH_ALL=false; shift ;;
|
||||
--ktor) SEARCH_KTOR=true; SEARCH_ALL=false; shift ;;
|
||||
--apollo) SEARCH_APOLLO=true; SEARCH_ALL=false; shift ;;
|
||||
--volley) SEARCH_VOLLEY=true; SEARCH_ALL=false; shift ;;
|
||||
--urls) SEARCH_URLS=true; SEARCH_ALL=false; shift ;;
|
||||
--auth) SEARCH_AUTH=true; SEARCH_ALL=false; shift ;;
|
||||
|
|
@ -90,6 +96,27 @@ if [[ "$SEARCH_ALL" == true || "$SEARCH_OKHTTP" == true ]]; then
|
|||
run_grep '(\.url\s*\(|\.addQueryParameter|\.addPathSegment|\.scheme\s*\(|\.host\s*\()'
|
||||
fi
|
||||
|
||||
# --- Ktor (Kotlin) ---
|
||||
# Ktor doesn't use annotations. Endpoints appear as string args to
|
||||
# client.get/post/etc., or are built via HttpRequestBuilder.url(...). Auth
|
||||
# is configured via the bearer { loadTokens / refreshTokens } DSL.
|
||||
if [[ "$SEARCH_ALL" == true || "$SEARCH_KTOR" == true ]]; then
|
||||
section "Ktor — Client Calls"
|
||||
run_grep '\b(client|httpClient|HttpClient)\.(get|post|put|delete|patch|head|request)\s*[<(]'
|
||||
section "Ktor — Request Building / Default Request"
|
||||
run_grep '(HttpRequestBuilder|defaultRequest\s*\{|\burl\s*\(\s*"|URLBuilder|URLProtocol)'
|
||||
section "Ktor — Auth Plugin (Bearer / Refresh)"
|
||||
run_grep '(\bbearer\s*\{|BearerTokens\s*\(|loadTokens\s*\{|refreshTokens\s*\{|\bAuth\s*\)\s*\{)'
|
||||
fi
|
||||
|
||||
# --- Apollo (GraphQL) ---
|
||||
if [[ "$SEARCH_ALL" == true || "$SEARCH_APOLLO" == true ]]; then
|
||||
section "Apollo — GraphQL Client"
|
||||
run_grep '(ApolloClient|\.serverUrl\s*\(|\.subscriptionNetworkTransport|HttpNetworkTransport)'
|
||||
section "Apollo — Operations"
|
||||
run_grep '(\.query\s*\(\s*[A-Z]|\.mutation\s*\(\s*[A-Z]|\.subscription\s*\(\s*[A-Z])'
|
||||
fi
|
||||
|
||||
# --- Volley ---
|
||||
if [[ "$SEARCH_ALL" == true || "$SEARCH_VOLLEY" == true ]]; then
|
||||
section "Volley Requests"
|
||||
|
|
|
|||
Loading…
Reference in New Issue