Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
13f6a4f
fix(nodejs): honour cookie scope and stop truncating token values
JeanExtreme002 Aug 19, 2026
77870fb
build(deps): raise dependency floors past known advisories
JeanExtreme002 Aug 19, 2026
894be48
fix(nodejs): correct cookie edge cases found in review
JeanExtreme002 Aug 20, 2026
d9216f6
fix(nodejs): sync request() types and cover the redirect path
JeanExtreme002 Aug 20, 2026
d2103e1
test(nodejs): make the redirect test work on node 18
JeanExtreme002 Aug 20, 2026
1a4e5d7
fix: bound response decompression in both ports
JeanExtreme002 Aug 20, 2026
12ea74d
ci: pin actions to SHAs, pin docs deps, and enforce the audits
JeanExtreme002 Aug 20, 2026
5ea775b
chore(release): 1.5.4
JeanExtreme002 Aug 20, 2026
1e158a3
ci: deploy docs from the Pages artifact instead of gh-pages
JeanExtreme002 Aug 20, 2026
66bd319
fix: reject truncated bodies and handle BOM after the budget change
JeanExtreme002 Aug 20, 2026
ff4850d
fix(python): stream the body so the size budget actually applies
JeanExtreme002 Aug 20, 2026
8046fb1
revert(python): stop streaming the body; the cure cost more than the …
JeanExtreme002 Aug 20, 2026
e6f3747
fix(python): take content decoding from libcurl so the budget is real
JeanExtreme002 Aug 20, 2026
8763937
fix: harden the encodings this code is now responsible for
JeanExtreme002 Aug 20, 2026
d76a911
refactor: separate the two size budgets and make the rest self-enforcing
JeanExtreme002 Aug 20, 2026
104c5ee
fix: close the holes the last two rounds of budget work opened
JeanExtreme002 Aug 20, 2026
8b83af4
fix: restore two decoding behaviours libcurl used to provide
JeanExtreme002 Aug 20, 2026
06c5af6
fix: restore the public cookie shape and bank cookies from blocked re…
JeanExtreme002 Aug 20, 2026
4223818
fix(nodejs): stop the error-path cookies leaking and mis-attributing
JeanExtreme002 Aug 20, 2026
89ac1e6
feat!: drop the deprecated FlightRadar24 import alias
JeanExtreme002 Aug 20, 2026
5d25e38
perf: collect gzip members instead of concatenating, and fix stale docs
JeanExtreme002 Aug 21, 2026
9964a62
perf(python): stop holding the decoded body three times over
JeanExtreme002 Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/docs-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pinned so a compromised release cannot be pulled in automatically: these
# packages execute during `mkdocs build`, inside the job that publishes the
# docs site. Bump deliberately, not implicitly.
mkdocs-material==9.7.7
mkdocs-git-committers-plugin-2==2.5.0
2 changes: 1 addition & 1 deletion .github/workflows/delete-pr-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const pr = context.payload.pull_request;
Expand Down
49 changes: 34 additions & 15 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,53 @@
name: Deploy MkDocs
name: Deploy MkDocs
on:
push:
branches:
- main
paths:
- 'mkdocs.yml'
- 'docs/**'
- '.github/docs-requirements.txt'
- '.github/workflows/deploy-docs.yml'

# Pages is served from the Actions artifact, so nothing here needs to push to
# the repository: a compromised docs dependency gets no write access.
permissions:
contents: write
contents: read
pages: write
id-token: write

# One deploy at a time, and never cancel one midway.
concurrency:
group: pages
cancel-in-progress: false

jobs:
deploy:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install \
mkdocs-material \
mkdocs-git-committers-plugin-2
- run: mkdocs gh-deploy --force
- run: pip install -r .github/docs-requirements.txt
- run: mkdocs build
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: site

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
2 changes: 1 addition & 1 deletion .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
name: Apply PR labels
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const pr = context.payload.pull_request;
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint-pr-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Lint PR title
uses: amannn/action-semantic-pull-request@v5
uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down
17 changes: 8 additions & 9 deletions .github/workflows/node-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ jobs:
matrix:
node-version: ['18.x', '20.x', '22.x']
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- name: Set up NodeJS ${{ matrix.node-version }}
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
Expand All @@ -41,16 +41,15 @@ jobs:
- name: Offline tests (PR gate)
run: npm run test:offline
- name: Integration tests (live FR24)
uses: nick-fields/retry@v3
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
with:
timeout_minutes: 10
max_attempts: 3
command: cd nodejs && npm run test:integration
continue-on-error: ${{ github.event_name == 'push' }}
- name: Dependency audit (informational)
# Informational only: surfaces high-severity advisories as a soft-fail
# without blocking PRs. Re-enable enforcement (drop continue-on-error)
# once the audit baseline is clean.
- name: Dependency audit (shipped dependencies)
# Enforced, and no `cd`: this job already defaults into ./nodejs, so the
# old `cd nodejs` failed every run and continue-on-error hid it, which
# is how the undici floor stayed vulnerable unnoticed.
if: matrix.node-version == '22.x'
continue-on-error: true
run: cd nodejs && npm audit --omit=dev --audit-level=high
run: npm audit --omit=dev --audit-level=high
12 changes: 6 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
verify-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

- name: Read declared versions
id: versions
Expand Down Expand Up @@ -61,10 +61,10 @@ jobs:
permissions:
id-token: write # Required for trusted publishing (OIDC)
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.13'

Expand All @@ -84,7 +84,7 @@ jobs:

- name: Publish to PyPI
if: github.event_name == 'release' || inputs.dry_run == false
uses: pypa/gh-action-pypi-publish@release/v1
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
packages-dir: python/dist/

Expand All @@ -99,10 +99,10 @@ jobs:
run:
working-directory: ./nodejs
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

- name: Set up NodeJS
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '22.x'
registry-url: 'https://registry.npmjs.org'
Expand Down
28 changes: 19 additions & 9 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ jobs:
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -34,25 +34,35 @@ jobs:
pip install -e "./python[tests]"
pip install flake8 mypy build pytest-cov pip-audit
- name: Lint
run: cd python && python -m flake8 FlightRadarAPI FlightRadar24 tests
run: cd python && python -m flake8 FlightRadarAPI tests
- name: Type check
run: cd python && python -m mypy FlightRadarAPI --ignore-missing-imports
- name: Offline tests (PR gate)
run: cd python && pytest -m "not integration" --cov=FlightRadarAPI --cov-report=term --cov-report=xml -v
- name: Integration tests (live FR24)
uses: nick-fields/retry@v3
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3
with:
timeout_minutes: 10
max_attempts: 3
command: cd python && pytest -m integration -vv -s
continue-on-error: ${{ github.event_name == 'push' }}
- name: Dependency audit (informational)
# Informational only: surfaces vulnerable transitive deps as a soft-fail
# without blocking PRs. Re-enable enforcement (drop continue-on-error)
# once the audit baseline is clean.
- name: Dependency audit (shipped dependencies)
# Enforced, and scoped to what users actually install: a vulnerable dev
# tool must not block every PR, but a vulnerable runtime dep must.
if: matrix.python-version == '3.13'
run: |
python -m venv /tmp/shipenv
/tmp/shipenv/bin/pip install --quiet --upgrade pip
/tmp/shipenv/bin/pip install --quiet ./python
/tmp/shipenv/bin/pip freeze | grep -v "^FlightRadarAPI" > /tmp/shipped.txt
cat /tmp/shipped.txt
pip-audit -r /tmp/shipped.txt
- name: Dependency audit (dev toolchain, informational)
if: matrix.python-version == '3.13'
continue-on-error: true
run: pip-audit --skip-editable -r <(pip freeze | grep -v "^FlightRadarAPI")
run: |
pip freeze | grep -v "^FlightRadarAPI" > /tmp/devenv.txt
pip-audit -r /tmp/devenv.txt
- name: Build and verify install
run: |
python -m build ./python
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ venv/
.mypy_cache/
.pytest_cache/
htmlcov/
site/
.coverage
coverage.xml

Expand Down
14 changes: 12 additions & 2 deletions nodejs/FlightRadarAPI/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,24 @@ class CloudflareError extends FlightRadarError {
/**
* @param {string} message
* @param {object} response
* @param {string} [body] - the challenge page, already read off `response`
*/
constructor(message, response) {
constructor(message, response, body) {
super(message);
this.response = response;
// `response.bodyUsed` is true by the time this is thrown: the body has
// to be drained for the connection to survive. Carry it so the page is
// still readable, which is the point of exposing the response at all.
this.body = body;
}
}

/** Thrown when a response body exceeds the size budget. */
class DecompressionLimitError extends FlightRadarError {}

/** Thrown when login fails or an authenticated endpoint is accessed without login. */
class LoginError extends FlightRadarError {}

module.exports = { FlightRadarError, AirportNotFoundError, CloudflareError, LoginError };
module.exports = {
FlightRadarError, AirportNotFoundError, CloudflareError, DecompressionLimitError, LoginError,
};
12 changes: 9 additions & 3 deletions nodejs/FlightRadarAPI/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ export interface ImpersonateOptions {
*/
export class APIClient {
constructor(options?: { impersonate?: ImpersonateOptions; retry?: RetryPolicy });
request(url: string, options?: object): Promise<{content: any; statusCode: number; cookies: Record<string, string>}>;
request(url: string, options?: object): Promise<{content: any; statusCode: number; cookies: Record<string, string>; rawCookies: string[]; url: string}>;
/**
* Make a stateless request that bypasses the shared cookie jar. Safe to
* call from concurrent fan-outs.
*/
requestStandalone(url: string, options?: object): Promise<{content: any; statusCode: number; cookies: Record<string, string>}>;
requestStandalone(url: string, options?: object): Promise<{content: any; statusCode: number; cookies: Record<string, string>; rawCookies: string[]; url: string}>;
getCookie(name: string): string | undefined;
clearCookies(): void;
/** Drop a single cookie, leaving the rest of the jar intact. */
Expand Down Expand Up @@ -517,7 +517,13 @@ export class AirportNotFoundError extends FlightRadarError {

export class CloudflareError extends FlightRadarError {
response: any;
constructor(message?: string, response?: any);
/** The challenge page, read off `response` before it was consumed. */
body?: string;
constructor(message?: string, response?: any, body?: string);
}

export class DecompressionLimitError extends FlightRadarError {
constructor(message?: string);
}

export class LoginError extends FlightRadarError {
Expand Down
6 changes: 4 additions & 2 deletions nodejs/FlightRadarAPI/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
* https://www.flightradar24.com/terms-and-conditions
*/

const { FlightRadarError, AirportNotFoundError, CloudflareError, LoginError } = require("./errors");
const {
FlightRadarError, AirportNotFoundError, CloudflareError, DecompressionLimitError, LoginError,
} = require("./errors");
const FlightRadar24API = require("./api");
const FlightTrackerConfig = require("./flightTrackerConfig");
const Airport = require("./entities/airport");
Expand All @@ -25,7 +27,7 @@ module.exports = {
FlightTrackerConfig,
Countries,
Airport, Entity, Flight,
FlightRadarError, AirportNotFoundError, CloudflareError, LoginError,
FlightRadarError, AirportNotFoundError, CloudflareError, DecompressionLimitError, LoginError,
RetryPolicy, APIClient,
author, version,
};
Loading
Loading