fix: encode path parameters in request URLs - #1113
Open
max-programming wants to merge 7 commits into
Open
max-programming wants to merge 7 commits into
max-programming wants to merge 7 commits into
Conversation
…arameters # Conflicts: # src/api-keys/api-keys.ts # src/automation-runs/automation-runs.ts # src/automations/automations.ts # src/broadcasts/broadcasts.ts # src/contact-properties/contact-properties.ts # src/contacts/contacts.ts # src/contacts/imports/contact-imports.ts # src/contacts/segments/contact-segments.ts # src/domains/claims/domain-claims.ts # src/domains/domains.ts # src/emails/attachments/attachments.ts # src/emails/emails.ts # src/emails/receiving/attachments/attachments.ts # src/emails/receiving/receiving.ts # src/events/events.ts # src/logs/logs.ts # src/oauth-grants/oauth-grants.ts # src/resend.spec.ts # src/resend.ts # src/segments/segments.ts # src/suppressions/suppressions.ts # src/templates/templates.ts # src/topics/topics.ts # src/webhooks/events/events.ts # src/webhooks/webhooks.ts
… fix/encode-path-parameters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
what's happening
most resource methods drop ids and emails straight into the request path:
only
events.tsandsuppressions.tsrun the value throughencodeURIComponent.contacts can be looked up by email, and
#,/,?and%are all valid in the local part of an email. forjohn#doe@example.com, everything after#is treated as a url fragment and never sent, soresend.contacts.get({ email: 'john#doe@example.com' })ends up requesting/contacts/john. same thing happens forupdateandremove, so an update or delete can hit the wrong contact.a/b@example.comsplits into an extra path segment, anda?b@example.comturns into a query string.there's a hardening side too. url paths work like folders, and
..means "go up one level", sofetchresolves/domains/../api-keysto/api-keysbefore sending. if an app passes user input as an id, that lets a call escape its own endpoint:domains.remove('../api-keys/KEY_ID')sendsDELETE /api-keys/KEY_ID, which is the delete api key endpoint.x?foo=baralso sneaks in extra query params.the fix
added a small
pathtagged template insrc/common/utils/path.tsthat encodes every interpolated value:switched every interpolated request path over to it, including
events.tsandsuppressions.ts, so there's one pattern and new code can't forget. for paths with a query string only the path part goes throughpath, the query string is left as is.encoding the
/is enough for../api-keys(it becomes one harmless segment,..%2Fapi-keys), but not for an id that is exactly.or... there's no/to encode, and url parsing treats%2E%2Eas..too, so there's no way to send it that stays on the right endpoint.fetchRequestnow checks for that and returns aninvalid_parametererror without sending anything. it returns the error instead of throwing, same as the other input checks in the sdk. ids that just contain dots (...,john.doe@...) go through as normal.normal ids come out unchanged, so this is non-breaking. the one visible difference is that
@is now sent as%40, which the api already handles (suppressions and events send it that way today, and the re-recorded fixtures below confirm it for contacts).tests
path.spec.tscovers the helper: plain ids unchanged, reserved characters encoded,../kept inside one segment, and dot segment detection including the encoded formsresend.spec.ts:./..ids returninvalid_parameterand no request is made,...still goes throughcontacts.spec.ts: lookups byjohn#doe@example.comanda/b@example.comhit the encoded path, a normal id is unchanged. the existing string-email test now expectsteam%40resend.comone heads up:
lists contacts without paginationfails when recording on an account that isn't empty, becausecreates a contactleavestest@example.combehind and the list test expects exactly 6. it's not related to this change, so i kept the existing fixture for that test.verified
built the sdk from the current release and from this pr, pointed both at a local http server via
baseUrl, and logged the request that actually arrived for each call:contacts.get({ email: 'john#doe@example.com' })GET /contacts/johnGET /contacts/john%23doe%40example.comcontacts.update({ email: 'john#doe@example.com', ... })PATCH /contacts/johnPATCH /contacts/john%23doe%40example.comcontacts.remove({ email: 'john#doe@example.com' })DELETE /contacts/johnDELETE /contacts/john%23doe%40example.comcontacts.get({ email: 'a/b@example.com' })GET /contacts/a/b@example.comGET /contacts/a%2Fb%40example.comemails.get('x?foo=bar')GET /emails/x?foo=barGET /emails/x%3Ffoo%3Dbardomains.remove('../api-keys/KEY_ID')DELETE /api-keys/KEY_IDDELETE /domains/..%2Fapi-keys%2FKEY_IDemails.cancel('..')POST /cancelinvalid_parameter/emailstodayemails.get('..')GET /invalid_parameter/emailstodayemails.get('...')GET /emails/...GET /emails/...broadcasts.get('<uuid>')GET /broadcasts/<uuid>GET /broadcasts/<uuid>templates.list({ limit: 10, after: 'abc' })GET /templates?after=abc&limit=10GET /templates?after=abc&limit=10Summary by cubic
Fixes path construction in request URLs so IDs and emails with reserved characters like
#,/,?, and%are correctly encoded, preventing lookups and updates from hitting the wrong contact or endpoint.Refactors
pathtagged template that encodes every interpolated value, and switches all resource methods to it; plain IDs come out unchanged, so this is non-breaking.events.tsandsuppressions.tsnow use the same pattern instead of the previousencodeURIComponentcalls.Bug Fixes
#in emails so they aren't treated as URL fragments, and/so it stays one path segment..and..path parameters infetchRequestwith aninvalid_parametererror without sending a request, closing the path traversal hole wheredomains.remove('../api-keys/KEY_ID')would hit the delete API key endpoint.Written for commit 2cea0cb. Summary will update on new commits.